<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="ssdut dsa web" />
    <meta name="author" content="" />

    <title>ssdut.DSA/线性表/单链表</title>
    <link rel="stylesheet" href="../assets/css/fonts/linecons/css/linecons.css">
    <link rel="stylesheet" href="../assets/css/fonts/fontawesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="../assets/css/bootstrap.css">
    <link rel="stylesheet" href="../assets/css/xenon-core.css">
    <link rel="stylesheet" href="../assets/css/xenon-forms.css">
    <link rel="stylesheet" href="../assets/css/xenon-components.css">
    <link rel="stylesheet" href="../assets/css/xenon-skins.css">
    <link rel="stylesheet" href="../assets/css/custom.css">
    <link rel="stylesheet" type="text/css" href="../assets/css/stylesheet.css">
    <link rel="stylesheet" type="text/css" href="../assets/css/common.css">
    <link rel="stylesheet" href="../assets/css/viz-1.0.1.css">
    <link rel="stylesheet" href="../assets/css/visual.css">
    <link rel="stylesheet" href="../assets/css/drawgraph.css">


    <script src="../assets/js/jquery-3.3.1.min.js"></script>

</head>

<body class="page-body">
    <div class="page-container">
        <!-- add class"sidebar-collapsed" to close sidebar by default,"chat-visible" to make chat appear always -->

        <!-- Add"fixed" class to make the sidebar fixed always to the browser viewport. -->
        <!-- Adding class"toggle-others" will keep only one menu item open at a time. -->
        <!-- Adding class"collapsed" collapse sidebar root elements and show only icons. -->
        <div class="sidebar-menu toggle-others fixed">

            <div class="sidebar-menu-inner">

                <header class="logo-env">
                    <!-- logo -->
                    <div class="logo">
                        <a href="../" class="logo-expanded">
                            <img src="../assets/images/logo@2x.png" width="80" alt="" />
                        </a>

                        <a href="../" class="logo-collapsed">
                            <img src="../assets/images/logo-collapsed@2x.png" width="40" alt="" />
                        </a>
                    </div>
                  
                </header>
                <ul id="main-menu" class="main-menu">
                    <!-- add class"multiple-expanded" to allow multiple submenus to open -->
                    <!-- class"auto-inherit-active-class" will automatically add"active" class for parent elements who are marked already with class"active" -->
                    <li >
                        <a href="../index.html">
                            <i class="fa-home"></i>
                            <span class="title">首页</span>
                        </a>
                    </li>
                    <li class="opened active">
                        <a href="../list/ll.html">
                            <i class="fa-chain"></i>
                            <span class="title">线性表</span>
                        </a>
                        <ul>
                            <li class="active">
                                <a href="../list/ll.html">
                                    <span class="title">单链表</span>
                                </a>
                            </li>
                            <li>
                                <a href="../list/stack.html">
                                    <span class="title">栈</span>
                                </a>
                            </li>
                            <li>
                                <a href="../list/queue.html">
                                    <span class="title">队列</span>
                                </a>
                            </li>
                            <li>
                                <a href="../list/dll.html">
                                    <span class="title">双向链表</span>
                                </a>
                            </li>
                            <li>
                                <a href="../list/deque.html">
                                    <span class="title">双端队列</span>
                                </a>
                            </li>

                        </ul>
                    </li>
                    <li>
                        <a href="../tree/bst.html">
                            <i class="fa-sitemap"></i>
                            <span class="title">二叉树</span>
                        </a>
                        <ul>
                            <li>
                                <a href="../tree/bst.html">
                                    <span class="title">二叉搜索树</span>
                                </a>
                            </li>
                            <li>
                                <a href="../tree/avl.html">
                                    <span class="title">平衡二叉搜索树</span>
                                </a>
                            </li>
                            <li>
                                <a href="../tree/heap.html">
                                    <span class="title">堆</span>
                                </a>
                            </li>
                        </ul>
                    </li>
                    <li>
                        <a href="../graph/graphds.html">
                            <i class="fa-share-alt"></i>
                            <span class="title">图</span>
                        </a>
                        <ul>
                            <li>
                                <a href="../graph/graphds.html">
                                    <span class="title">图的数据结构</span>
                                </a>
                            </li>
                            <li>
                                <a href="../graph/dfsbfs.html">
                                    <span class="title">图的遍历</span>
                                </a>
                            </li>
                            <li>
                                <a href="../graph/mst.html">
                                    <span class="title">最小生成树</span>
                                </a>
                            </li>
                            <li>
                                <a href="../graph/sssp.html">
                                    <span class="title">最短路径</span>
                                </a>
                            </li>
                            <li>
                                <a href="../graph/maxflow.html">
                                    <span class="title">网络最大流</span>
                                </a>
                            </li>
                        </ul>
                    </li>
                    <li>
                        <a href="../hashtable/lp.html">
                            <i class="fa-random"></i>
                            <span class="title">散列表</span>                          
                        </a>
                        <ul>
                            <li>
                                <a href="../hashtable/lp.html">
                                    <span class="title">线性探查</span>
                                </a>
                            </li>
                            <li>
                                <a href="../hashtable/qp.html">
                                    <span class="title">二次探查</span>
                                </a>
                            </li>
                            <li>
                                <a href="../hashtable/dh.html">
                                    <span class="title">双散列</span>
                                </a>
                            </li>
                            <li>
                                <a href="../hashtable/sc.html">
                                    <span class="title">分离链接</span>
                                </a>
                            </li>
                        </ul>
                    </li>
                    <li >
                        <a href="../sorting/bubble.html" >
                            <i class="fa-sort-amount-asc"></i>
                            <span class="title">排序</span>
                        </a>
                        <ul>
                            <li>
                                <a href="../sorting/bubble.html">
                                    <span class="title">冒泡排序</span>
                                </a>
                            </li>
                            <li>
                                <a href="../sorting/selection.html">
                                    <span class="title">选择排序</span>
                                </a>
                            </li>
                            <li>
                                <a href="../sorting/insertion.html">
                                    <span class="title">插入排序</span>
                                </a>
                            </li>
                            <li>
                                <a href="../sorting/merge.html">
                                    <span class="title">归并排序</span>
                                </a>
                            </li>
                            <li>
                                <a href="../sorting/quick.html">
                                    <span class="title">快速排序</span>
                                </a>
                            </li>
                            <li >
                                <a href="../sorting/radix.html" >
                                    <span class="title">基数排序</span>
                                </a>
                            </li>
                        </ul>
                    </li>             
                </ul>
            </div>
        </div>

        <div class="main-content">

            <!-- User Info, Notifications and Menu Bar -->
          
                <div class="row" style="margin:-30px -30px 0 -30px; background-color: #FFF; padding:15px 10px 10px; ">
                    <div class="col-auto">
                        <ul class="user-info-menu left-links list-inline list-unstyled">
                            <li class="hidden-sm hidden-xs">
                                <a href="#" data-toggle="sidebar">
                                    <i class="fa-bars"></i>
                                </a>
                            </li>
                        </ul>        
                    </div>
                    <!-- Left links for user info navbar -->
                    <div class="col-auto">
                        <h4 id="page-title" >链表</h4>
                    </div>
                    <div class="col-auto me-auto">
                        <div id="current-action" ></div>
                    </div>               
                    <div class="col-auto" >
                                    <!-- Right links for user info navbar -->              
                        <div id="speed-control">
                            减速
                            <div id="speed-input" class="ui-slider ui-corner-all ui-slider-horizontal ui-widget ui-widget-content">
                                <span tabindex="0" class="ui-slider-handle ui-corner-all ui-state-default" style="left: 72.2222%;"></span>
                            </div>
                            加速
                        </div>              
                    </div>
                </div>
            

            <script type="text/javascript">
                jQuery(document).ready(function($) {     
                    // Charts
                    var xenonPalette = ['#68b828', '#7c38bc', '#0e62c7', '#fcd036', '#4fcdfc', '#00b19d', '#ff6264', '#f7aa47'];
                    // Pageviews Visitors Chart
                    SOP();
                        displayList();
                   
                        lw.setActiveStatus("list");
                        $("#page-title").text('单链表');
                });
               


                function between(randNumMin, randNumMax) {
                    var randInt = Math.floor((Math.random() * ((randNumMax + 1) - randNumMin)) + randNumMin);

                    return randInt;
                }
            </script>

            <div class="row">

             
                <div id="dark-overlay"></div>


                <div id="viz">

                </div>
                

                <div id="overlay" hidden="" style="opacity: 0; display: none;"></div>


                <div id="popup" hidden="">
                    <div id="popup-content"></div>
                    <span id="hide-popup" hidden="" style="background-color: rgb(255, 138, 39);">X <u>关闭</u></span>
                </div>
         

                <script>
                    var PHP_DOMAIN ="";

                    // surprise colour!
                    // Referenced to in  home.js and viz.js also
                    var colourArray = ["#52bc69","#d65775" /*"#ed5a7d"*/ ,"#2ebbd1","#d9513c","#fec515","#4b65ba","#ff8a27","#a7d41e"]; // green, pink, blue, red, yellow, indigo, orange, lime

                    function disableScroll() {
                        $('html').css('overflow', 'hidden');
                    }

                    function enableScroll() {
                        $('html').css('overflow', 'visible');
                    }

                    function replaceAll(find, replace, str) {
                        return str.replace(new RegExp(find, 'g'), replace);
                    }

                    function getColours() {
                        var generatedColours = new Array();
                        while (generatedColours.length < 4) {
                            var n = (Math.floor(Math.random() * colourArray.length));
                            if ($.inArray(n, generatedColours) == -1)
                                generatedColours.push(n);
                        }
                        return generatedColours;
                    }

                    function isOn(value, position) {
                        return (value >> position) & 1 === 1;
                    }

                    function customAlert(msg) {
                        $('#custom-alert p').html(msg);
                        var m = -1 * ($('#custom-alert').outerHeight() / 2);
                        $('#custom-alert').css('margin-top', m + 'px');
                        $('#dark-overlay').fadeIn(function() {
                            $('#custom-alert').fadeIn(function() {
                                setTimeout(function() {
                                    $('#custom-alert').fadeOut(function() {
                                        $('#dark-overlay').fadeOut();
                                    });
                                }, 1000);
                            });
                        });
                    }

                    function showLoadingScreen() {
                        $('#loading-overlay').show();
                        $('#loading-message').show();
                    }

                    function hideLoadingScreen() {
                        $('#loading-overlay').hide();
                    }

                    function commonAction(retval, msg) {
                        //setTimeout(function() {
                        if (retval) { // mode =="exploration" && // now not only for exploration mode, but check if this opens other problems
                         
                            $('#current-action').html(mode =="exploration" ? msg : ("e-Lecture Example (auto play until done)<br>" + msg));
                            $('#progress-bar').slider("option","max", gw.getTotalIteration() - 1);
                            triggerRightPanels();
                            isPlaying = true;
                        }
                        //}, 500);
                    }

                    function getQueryVariable(variable) {
                        var query = window.location.search.substring(1);
                        var vars = query.split('&');
                        for (var i = 0; i < vars.length; i++) {
                            var pair = vars[i].split('=');
                            if (decodeURIComponent(pair[0]) == variable)
                                return decodeURIComponent(pair[1]);
                        }
                        return"";
                    }

                    var generatedColours = getColours();
                    var surpriseColour = colourArray[generatedColours[0]];
                    var colourTheSecond = colourArray[generatedColours[1]];
                    var colourTheThird = colourArray[generatedColours[2]];
                    var colourTheFourth = colourArray[generatedColours[3]];

                    $(function() {
                       

                        // title
                        $('#title a').click(function() {
                            $('#title a').removeClass('selected-viz');
                            $(this).addClass('selected-viz');
                            // temporary quick fix for Google Chrome Aug 2016 issue...
                            setTimeout(function() {
                                document.body.style.zoom ="100.1%";
                            }, 100); // force resize/redraw...
                            setTimeout(function() {
                                document.body.style.zoom ="100%";
                            }, 600);
                        });

                        // overlays stuffs
                        $('#trigger-about').click(function() {
                            if ($(window).width() > 600) {
                                $('#dark-overlay').fadeIn(function() {
                                    $('#about').fadeIn();
                                });
                            } else
                                alert('Sorry, this dialog is too big. Please load it on bigger screen');
                        });

                        $('#trigger-team').click(function() {
                            if ($(window).width() > 600) {
                                $('#dark-overlay').fadeIn(function() {
                                    $('#team').fadeIn();
                                });
                            } else
                                alert('Sorry, this dialog is too big. Please load it on bigger screen');
                        });

                        $('#trigger-terms').click(function() {
                            if ($(window).width() > 600) {
                                $('#dark-overlay').fadeIn(function() {
                                    $('#termsofuse').fadeIn();
                                });
                            } else
                                alert('Sorry, this dialog is too big. Please load it on bigger screen');
                        });

                        $('.close-overlay').click(function() {
                            $('.overlays').fadeOut(function() {
                                $('#dark-overlay').fadeOut();
                            });
                        });

                        $('#dark-overlay').click(function() {
                            $('.overlays').fadeOut();
                            $('#dark-overlay').fadeOut();
                        });
                    });
                </script>




                <script>
                    window.onpopstate = function(event) {
                        var slide = event.state['slide'];
                        openSlide(slide, function() {
                            runSlide(slide);
                        });
                    };

                    function getUrlParameter(sParam) {
                        var sPageURL = decodeURIComponent(window.location.search.substring(1)),
                            sURLVariables = sPageURL.split('&'),
                            sParameterName, i;

                        for (i = 0; i < sURLVariables.length; i++) {
                            sParameterName = sURLVariables[i].split('=');
                            if (sParameterName[0] === sParam) return sParameterName[1] === undefined ? true : sParameterName[1];
                        }
                    };

                    function pushState(slideValue) {
                        var url = '/zh/list';
                        if (typeof slideValue != 'undefined' && slideValue != null) url += '?slide=' + slideValue;
                        window.history.pushState({
                            slide: slideValue
                        },"slide" + slideValue, url);
                    }

                    function showPopup(callback) {
                        $('#popup').fadeIn(100, callback);
                    }

                    function hidePopup(callback) {
                        $('#popup').fadeOut(100, callback);
                    }

                    $(function() {
                        var slide = getUrlParameter('slide');

          

                        $('.mcq-submit').click(function() {
                            var questionId = parseInt($(this).attr('id').split('-')[1]);
                            var answer = $('#mcq-answer-' + questionId).val();
                            var userAnswer = $('input[type=radio][name=mcq-' + questionId + '-choice]:checked').val();

                            if (answer === userAnswer) {
                                $('#answer-status-' + questionId).html('<font color="green"><b>Correct!</b></font>');
                            } else {
                                $('#answer-status-' + questionId).html('<font color="red"><b>Wrong Answer! Try again...</b></font>');
                            }
                            $('#answer-status-' + questionId).show();
                            setTimeout(function() {
                                $('#answer-status-' + questionId).fadeOut(1000);
                            }, 1000);
                        });

                        $('.msq-submit').click(function() {
                            var questionId = parseInt($(this).attr('id').split('-')[1]);
                            var answer = $('#msq-answer-' + questionId).val();

                            var answers = [];
                            $('input[type=checkbox][class=msq-choice]:checked').each(function() {
                                answers.push($(this).attr('id').split('-')[3]);
                            });
                            answers.sort();
                            var userAnswer = answers.join(',');

                            if (answer === userAnswer) {
                                $('#answer-status-' + questionId).html('<font color="green">Correct!</font>');
                            } else {
                                $('#answer-status-' + questionId).html('<font color="red">Wrong Answer! Try again...</font>');
                            }
                            $('#answer-status-' + questionId).show();
                            setTimeout(function() {
                                $('#answer-status-' + questionId).fadeOut(1000);
                            }, 1000);
                        });

                      

                        $('#hide-popup').click(function() {
                            hidePopup();
                        });

                        $('#popup').hover(function() {
                            $('#hide-popup').show();
                        }, function() {
                            $('#hide-popup').hide();
                        });




                        // temporary quick fix for Google Chrome Aug 2016 issue..., put at last part so that everything else has been loaded
                        // setTimeout(function(){ document.body.style.zoom ="100.1%"; }, 500);
                        // setTimeout(function(){ document.body.style.zoom ="100%"; }, 600);
                        // I turn it off on 14 June 2018, seems 'ok'?
                    });

               

                    function adjustPopupToImageSize() {
                        var width = $('#popup-image').prop('width');
                        var height = $('#popup-image').prop('height');
                        $('#popup').width(width + 20);
                        $('#popup').height(height + 20);
                        if (width == 0 && height == 0) {
                            setTimeout(adjustPopupToImageSize, 200);
                        } else {
                            showPopup();
                        }
                    }

                    function POPUP_IMAGE(url) {
                        $('#popup-content').html('<img id="popup-image" src="' + url + '">');
                        adjustPopupToImageSize();
                    }

                    function URL(url) {
                        window.open(url, '_blank');
                    }

                </script>


            </div>






            <!-- Main Footer -->
            <!-- Choose between footer styles:"footer-type-1" or"footer-type-2" -->
            <!-- Add class"sticky" to  always stick the footer to the end of page (if page contents is small) -->
            <!-- Or class"fixed" to  always fix the footer to the end of page -->
            <footer class="main-footer sticky footer-type-2 sticky fixed">

                <div class="footer-inner">
                    <div class="row">
                        <div class="col-auto">
                            <div class="btn-group dropdown dropup">                               
                                <a id="actions-toggle" class="btn btn-sm btn-info dropdown-toggle " data-bs-toggle="dropdown"  data-bs-auto-close="outside" aria-haspopup="true" aria-expanded="false">                            
                                    操作                                                      
                                </a>                                    
                                <div id="actions" class="dropdown-menu">
                                    <div class="dropdown dropend">                                        
                                        <a id="create" class="dropdown-item dropdown-toggle" href="#"_id="dropdown-create" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">创建</a>
                                        <div class="dropdown-menu" aria-labelledby="dropdown-create">
                                            <div id="create-empty" class="dropdown-item" onclick="empty()" >
                                                <a>清空</a>
                                            </div>
                                            <div class="dropdown-divider"></div>
                                            <div id="create-random" class="dropdown-item" onclick="random()" >
                                                <a>随机</a>
                                            </div>
                                            <div id="create-random-sorted" class="dropdown-item" onclick="randomSorted()" >
                                                <a>随机排序</a>
                                            </div>
                                            <div class="dropdown-divider"></div>
                                            <div id="create-random-fixed-size" class="dropdown-header" >
                                                <p>随机固定大小</p>
                                            </div>                                           
                                            <div id="createfixedsize-input" class="  dropdown-item-text" >
                                                    <input type="number" id="v-create-size" class="inline" title="输入节点数" autocomplete="off" min="1" max="10" value="7">
                                                    <div id="createfixedsize-go" class="btn btn-sm btn-blue inline" onclick="randomFixedSize()" >
                                                        执行
                                                    </div>
                                            </div>   
                                            <div class="dropdown-divider"></div>
                                            <div id="create-from-arr" class="dropdown-header">
                                                <p>用户自定义列表&nbsp;</p>
                                            </div>
                                            <div id="createuserdefined-input" class="dropdown-item-text" >
                                                    <input type="text" id="v-create-arr" title="Enter the elements separated by comma" autocomplete="off" value="1,2,3" spellcheck="false" data-ms-editor="true">
                                                    <div id="createuserdefined-go" class="btn btn-sm btn-blue " onclick="nonRandom()" title="Create random fixed size linked list">
                                                        执行
                                                    </div>
                                            </div>                                            
                                        </div>
                                    </div>
                                    <div class="dropdown dropend">
                                        <a id="search" class="dropdown-item dropdown-toggle" href="#"_id="dropdown-search" data-bs-toggle="dropdown" aria-haspopup="true" data-bs-auto-close="outside"  aria-expanded="false">
                                            搜索</a>
                                        <div class="dropdown-menu" aria-labelledby="dropdown-search">
                                           
                                            <!-- <div id="create-random-fixed-size" class="dropdown-header" >
                                                <p>搜索方向</p>
                                            </div>    
                                            <div  class="dropdown-item-text" >                          
                                                <input type="radio" class="btn-check" name="search-direction" id="search-from-head" autocomplete="off" checked></input>
                                                <label class="btn btn-outline-success btn-sm" for="search-from-head">自头部</label>
                                                <input type="radio" class="btn-check" name="search-direction" id="search-from-tail" autocomplete="off" disabled></input>
                                                <label class="btn btn-outline-success btn-sm" for="search-from-tail">自尾部</label>
                                            </div> -->
                                            <div id="create-random-fixed-size" class="dropdown-header" >
                                                <p>搜索值</p>
                                            </div>    
                                            <div id="" class="  dropdown-item-text" >                          
                                                <div id="search-input" class="new-menu-option" style="float: left;"> <input type="number" id="v-search" title="Enter an Integer" autocomplete="off" min="0" max="99" value="5"></div>
                                                <div id="search-go" class="btn btn-sm btn-blue  " onclick="searchVertex()">
                                                    执行</div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="dropdown dropend">
                                        <a id="insert" class="dropdown-item dropdown-toggle" href="#"_id="dropdown-insert" data-bs-toggle="dropdown" aria-haspopup="true"   aria-expanded="false">
                                            插入</a>
                                        <div class="dropdown-menu " aria-labelledby="dropdown-insert" style="min-width: 200px;">
                                            <div  class="dropdown-item-text" >
                                                在头结点之前插入
                                            </div>   
                                            <div id="insert-head" class="dropdown-item-text" >
                                                <input type="number" id="v-insert-head-value" title="Enter an Integer" autocomplete="off" min="0" max="99" value="85">
                                                <div id="inserthead-go" class="btn btn-sm btn-blue " onclick="insertHead()" >
                                                    执行
                                                </div>                                          
                                            </div>
                                            <div class="dropdown-divider"></div>
                                            <div  class="dropdown-item-text" >
                                                在尾结点之后插入
                                            </div>  
                                            <div id="insert-tail" class="dropdown-item-text">                                            
                                                <input type="number" id="v-insert-tail-value" title="Enter an Integer" autocomplete="off" min="0" max="99" value="80">
                                                <div id="inserttail-go" class="btn btn-sm btn-blue " onclick="insertTail()">
                                                    执行
                                                </div>
                                            
                                            </div>
                                            <div class="dropdown-divider"></div>
                                            <div  class="dropdown-item-text" >
                                                在位置k插入
                                            </div>  
                                            <div id="insert-kth" class="dropdown-item-text">                                           
                                            <p class="inline">  插入位置： <input type="number" id="v-insert-kth" class="inline"  autocomplete="off" min="1" max="9" value="2"></p>
                                               <p> 插入值：<input type="number" id="v-insert-kth-value" title="Enter an Integer" autocomplete="off" min="0" max="99" value="90"></p>
                                                <div id="insertkth-go" class="btn btn-sm btn-blue " onclick="insertKth()">
                                                    执行
                                                </div>
                                           
                                            </div>
                                        </div>  
                                    </div>
                                    <div class="dropdown dropend">
                                        <a id="remove" class="dropdown-item dropdown-toggle" href="#"_id="dropdown-remove" data-bs-toggle="dropdown" aria-haspopup="true"   aria-expanded="false">
                                            移除</a>
                                        <div class="dropdown-menu " aria-labelledby="dropdown-remove" style="min-width: 200px;">
                                            <div id="remove-head" class="dropdown-item" onclick="removeHead()" >
                                                移除头部
                                            </div>
                                            <div id="remove-tail" class="dropdown-item"  onclick="removeTail()">
                                                移除尾部
                                            </div>
                                            <div class="dropdown-divider"></div>
                                            <div id="remove-kth" class="dropdown-item-text" >
                                                从位置k移除
                                            </div>
                                            <div id="removekth-input" class="dropdown-item-text" >
                                                <input type="number" id="v-remove-kth" title="Enter an Integer" autocomplete="off" min="1" max="8" value="2">
                                                <div id="removekth-go" class="btn btn-sm btn-blue " onclick="removeKth()" title="Remove k-th" >
                                                    执行
                                                </div>
                                            </div>
                                        </div>                                    
                                    </div>
                                </div>
                            </div>
                        </div>
                        
                        <div class="col-auto">
                            <span id="go-to-beginning" class="media-control-button" title="go to beginning" onclick="goToBeginning()"><img
                                src="../assets/images/goToBeginning.png" alt="go to beginning"></span>
                        </div>
                        <div class="col-auto">
                            <span id="previous" class="media-control-button" title="step backward" onclick="stepBackward()"><img
                                src="../assets/images/prevFrame.png" alt="previous frame"></span>
                        </div>
                        <div class="col-auto">
                            <span id="pause" class="media-control-button" title="pause" onclick="pause()" ><img
                                src="../assets/images/pause.png" alt="pause"></span>
                            <span id="play" class="media-control-button" title="play" onclick="play()" style="display: none;">
                                <img src="../assets/images/play.png" alt="play"></span>
                        </div>
                        <div class="col-auto">
                            <span id="next" class="media-control-button" title="step forward" onclick="stepForward()"><img
                                src="../assets/images/nextFrame.png" alt="next frame"></span>
                        </div>
                        <div class="col-auto">
                            <span id="go-to-end" class="media-control-button" title="go to end" onclick="goToEnd()"><img
                                src="../assets/images/goToEnd.png" alt="go to end"></span>
                        </div>


                        <div class="col-5 me-auto">
                            <div id="progress-bar" class="slider ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all" data-min="0" data-max="1800" data-value="223">
                            </div>

                        </div>
                        <div class="col-auto">
                            <div class="btn-group dropdown dropup">
                                <a id="codetrace-toggle" class="btn btn-sm btn-warning dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="false" aria-expanded="false" data-bs-offset="0,20">                            
                                    代码跟踪
                                                  
                                </a>
                                <div id="codetrace-panel" class="dropdown-menu dropdown-menu-end">
                                    <div class="row" style="width: 600px;">
                                        <div class="col-sm-12">
                                            <div id="status" class=" col-sm-12" >
                                                <p></p>
                                            </div>
                                            <div id="codetrace" class=" col-sm-12">
                                                <p id="code1" style="padding-top: 10px; background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                                <p id="code2" style="background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                                <p id="code3" style="background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                                <p id="code4" style="background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                                <p id="code5" style="background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                                <p id="code6" style="background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                                <p id="code7" style="padding-bottom: 10px; background-color: rgb(82, 188, 105); color: rgb(255, 255, 255);"></p>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                            </div>
                        </div>
                       </div>
            </footer>
        </div>
    </div>    

    <div class="page-loading-overlay">
        <div class="loader-2"></div>
    </div>

  


    <!-- Bottom Scripts -->
    <script src="../assets/js/bootstrap.bundle.js"></script>
    <script src="../assets/js/bootstrap5.dropdown.ml.hack.js"></script>
    <script src="../assets/js/TweenMax.min.js"></script>
    <script src="../assets/js/resizeable.js"></script>
    <script src="../assets/js/joinable.js"></script>
    <script src="../assets/js/xenon-api.js"></script>
    <script src="../assets/js/xenon-toggles.js"></script>


    <!-- Imported scripts on this page -->
    <script src="../assets/js/xenon-widgets.js"></script>
    <script src="../assets/js/devexpress-web-14.1/js/globalize.min.js"></script>
    <!--   <script src="../assets/js/devexpress-web-14.1/js/dx.chartjs.js"></script>-->
    <script src="../assets/js/toastr/toastr.min.js"></script>


    
    <script src="../assets/js/jquery-ui/jquery-ui.js"></script>
    <script src="../assets/js/knob/jquery.knob.min.js"></script>

    <!-- JavaScripts initializations and stuff -->
    <script src="../assets/js/xenon-custom.js"></script>
    
    <script src="../assets/js/d3.min.js"></script>
    <script src="../assets/js/viz-1.0.3.js"></script>
    <script src="../assets/js/visualgo_print.js"></script>
    <script src="../assets/js/graph_library.js"></script>

                <script type="text/javascript">
                    // List Widget
                    // original author: Steven Kester Yuwono, then cleaned and maintained by Steven Halim

                    var BACK_EDGE_CONST = 5000;

                    var List = function() {
                            var self = this;
                            var graphWidget = new GraphWidget();
                            var activeStatus ="list";
                            var maxSize = 10;
                            var maxStackSize = 7;

                            var valueRange = [1, 99]; // Range of valid values of List vertexes allowed
                            var maxHeightAllowed = 10;

                            var initialArray = [15, 6, 23, 4, 7, 71, 5, 50];
                            var initialStackArray = [15, 6, 50, 4];

                            /*
                             * iL: Internal representation of List in this object
                             * The keys are the text of the vertices, and the value is the attributes of the corresponding vertex encapsulated in a JS object, which are:
                             * -"prev": text of the prev vertex. If the vertex is root Vertex, the value is null
                             * -"next": text of the right child. No child -> null
                             * -"cx": X-coordinate of center of the vertex
                             * -"cy": Y-coordinate of center of the vertex
                             * -"height": height of the Vertex. Height of root is 0
                             * -"vtxIdx": Vertex class number of the corresponding Vertex
                             *
                             * In addition, there is a key called"head" in iL, containing the text of the root Vertex.
                             * If List is empty, root is null.
                             */

                            var iL = {};
                            var amountVertex = 0;
                            var vertexClassNumberCounter = 9;
                            iL["head"] = null;

                            init(generateRandomArray(Math.floor((Math.random() * 5 + 3))));

                            this.setActiveStatus = function(newActiveStatus) {
                                if (activeStatus != newActiveStatus) {
                                    clearScreen();
                                    activeStatus = newActiveStatus;
                                    init(generateRandomArray(Math.floor((Math.random() * 5 + 3))));
                                }
                            }

                            this.getActiveStatus = function() {
                                return activeStatus;
                            }

                            this.widgetRecalculatePosition = function() {
                                recalculatePosition();
                            }

                            this.getGraphWidget = function() {
                                return graphWidget;
                            }

                            /* FIRST MENU: Create */

                            this.generate = function(initArr) {
                                init(initArr);
                            }

                            function generateRandomArray(vertexAmt) {
                                var initArr = new Array();
                                while (initArr.length < vertexAmt) {
                                    var random = Math.floor(1 + Math.random() * 98);
                                    if ($.inArray(random, initArr) < 0)
                                        initArr.push(random);
                                }
                                return initArr;
                            }

                            this.generateRandom = function(isSorted) {
                                var initArr = generateRandomArray(Math.floor((Math.random() * 5 + 3))); // [3..7]
                                if (isSorted) initArr.sort(function(a, b) {
                                    return a - b;
                                }); // sort it first
                                init(initArr);
                                return true;
                            };

                            this.generateRandomFixedSize = function(val) {
                                if (activeStatus =="stack") {
                                    if (val > maxStackSize) {
                                        toastr.error('抱歉，最大的结点值上限为<span style="white-space: normal;">&nbsp;{maxSize}</span>'.replace("{maxSize}", maxStackSize), "错误");
                                       
                                        return false;
                                    }
                                } else {
                                    if (val > maxSize) {
                                        toastr.error('抱歉，最大的结点值上限为<span style="white-space: normal;">&nbsp;{maxSize}</span>'.replace("{maxSize}", maxStackSize), "错误");
                                        return false;
                                    }
                                }
                                var initArr = generateRandomArray(val);
                                init(initArr);
                                return true;
                            }

                            this.generateUserDefined = function(vertexTextArr) {
                                var vertexAmt = vertexTextArr.length;
                                if (activeStatus =="stack") {
                                    if (vertexAmt > maxStackSize) {
                                        toastr.error('抱歉，最大的结点值上限为<span style="white-space: normal;">&nbsp;{maxSize}</span>'.replace("{maxSize}", maxStackSize), "错误");
                                        return false;
                                    }
                                } else {
                                    if (vertexAmt > maxSize) {
                                        toastr.error('抱歉，最大的结点值上限为<span style="white-space: normal;">&nbsp;{maxSize}</span>'.replace("{maxSize}", maxStackSize), "错误");
                                        return false;
                                    }
                                }

                                if (vertexTextArr == '') { // prevent creation of empty list
                                    toastr.error('抱歉，最小的结点值为1', "错误");                                    
                                    return false;
                                }

                                var initArr = new Array();
                                for (i = 0; i < vertexTextArr.length; i++) {
                                    var vt = parseInt(vertexTextArr[i]);
                                    if (!isNaN(vt) && $.inArray(vt, initArr) < 0) // remove duplicates
                                        initArr.push(vt);
                                }
                                init(initArr);
                                return true;
                            }

                            this.getA = function() {
                                var theArr = [],
                                    currentVertex = iL["head"];
                                while (currentVertex != null) {
                                    theArr.push(currentVertex);
                                    currentVertex = iL[currentVertex]["next"];
                                }
                                return theArr;
                            }

                            /* SECOND MENU: Search (LL, DLL) or Peek (Stack, Queue, Deque -- additional Peek back) */

                            this.search = function(val, callback) {
                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = createState(iL),
                                    curVtxIdx, key, index = 0;

                                if (currentVertex == null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    // The current Linked List is empty, we return NOT_FOUND.
                                    cs["status"] = '现在的链表为空，我们返还“未找到”';
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);
                                } else {
                                    // temp = head, index = 0
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    curVtxIdx = iL[currentVertex]["vtxIdx"];
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][curVtxIdx]["extratext"] = curVtxIdx + (curVtxIdx == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/temp";
                                    // This is the current Linked List.
                                    // We want to search for value v = {val} starting from the head (index 0).
                                    cs["status"] = '这是现在的链表<div>我们想要从头部（下标为0）开始搜找值<span style="white-space: normal; font-size: 13px;">&nbsp;{val}&nbsp;</span></div>'.replace("{val}", val);
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);

                                    // while (temp.data != input)
                                    while (parseInt(currentVertex) != parseInt(val)) {
                                        vertexTraversed[currentVertex] = true;
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        // Comparing {currentVertex} with {val} (index = {index}).
                                        // {currentVertex} is not equal to {val} so we have to continue.
                                        cs["status"] = ('<span style="white-space: normal;">将 {currentVertex} 和 {val} (下标&nbsp;= {index}) 进行 比较.</span><br style="white-space: normal;"><span style="white-space: normal; '+
                                    '">{currentVertex} 不等于 {val} 所以我们继续</span>').replace("{currentVertex}", currentVertex).replace("{val}", val).replace("{index}", index).replace("{currentVertex}", currentVertex).replace("{val}", val);
                                        cs["vl"][curVtxIdx]["extratext"] = curVtxIdx + (curVtxIdx == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/temp";
                                        cs["lineNo"] = 3;
                                        stateList.push(cs);

                                        // case when vertex is not found
                                        currentVertex = iL[currentVertex]["next"];
                                        if (currentVertex == null) {
                                            // temp = temp.next, index++
                                            cs = createState(iL, vertexTraversed, edgeTraversed);
                                            // We try advancing temp to the next vertex.
                                            // But...
                                            cs["status"] = '我们试着将临时指针前进到下一个结点<div>但是......</div>';
                                            cs["lineNo"] = 4;
                                            stateList.push(cs);

                                            // if temp == null
                                            //   return -1
                                            cs = createState(iL, vertexTraversed, edgeTraversed);
                                            // temp is null (we have gone past the tail after O(N) step(s)).
                                            // We conclude that value {val} is NOT_FOUND in the Linked List.
                                            cs["status"] = '临时指针为空（我们已经距离尾部经过了O(N)步）<div>我们得到结论值<span style="white-space: normal; font-size: 13px;">{val} 在链表中“未找到”</span></div>'.replace("{val}", val);
                                            cs["lineNo"] = [5, 6];
                                            stateList.push(cs);

                                            break;
                                        }

                                        // temp = temp.next, index++
                                        // if temp == null
                                        curVtx = iL[currentVertex]["prev"];
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        var edgeHighlighted = iL[curVtx]["vtxIdx"];
                                        edgeTraversed[edgeHighlighted] = true;
                                        if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                            edgeTraversed[edgeHighlighted + BACK_EDGE_CONST] = true;
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][curVtxIdx]["extratext"] = curVtxIdx + (curVtxIdx == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/temp";
                                        cs["el"][edgeHighlighted]["animateHighlighted"] = true;
                                        cs["el"][edgeHighlighted]["state"] = EDGE_TRAVERSED;
                                        // So temp advances to the next vertex.
                                        // temp is not null, continue searching.
                                        cs["status"] = '所以临时前进到下一个结点<div>临时不为空，继续搜找</div>';
                                        cs["lineNo"] = [4, 5];
                                        stateList.push(cs);

                                        index++;
                                    }

                                    // case when vertex is found
                                    if (currentVertex != null) {
                                        // return index
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][curVtxIdx]["extratext"] = curVtxIdx + (curVtxIdx == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/temp";
                                        // Found value v = {val} at this highlighted vertex so we return index {index}.
                                        // The whole operation is O(N).
                                        cs["status"] = ('<span style="white-space: normal;">在这个高亮的节点找到了值{val}，所以我们返还下标 {index}&nbsp;</span><div><span style="white-space: normal;">整个操作的复杂度为O(N)</span><div><span style="white-space: normal; '+
                                    '"> </span></div><div><span style="white-space: normal;"> </span></div><div><span style="white-space: normal;"> </span></div><div><span style="white-space: normal;"> </span></div><div><span style="white-space: '+
                                    ' normal;"> </span></div></div>').replace("{val}", val).replace("{index}", index);
                                        cs["lineNo"] = 7;
                                        stateList.push(cs);
                                    }
                                }

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(4);
                                return true;
                            };

                            this.peek = function(isHead, callback) {
                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = createState(iL),
                                    curVtxIdx, key, index = 0;

                                if (currentVertex == null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    // The current Linked List is empty, we return NOT_FOUND.
                                    cs["status"] = '现在的链表为空，我们返还“未找到”';
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);
                                } else {
                                    if (!isHead) {
                                        while (true) { // go to tail
                                            if (iL[currentVertex]["next"] != null) currentVertex = iL[currentVertex]["next"];
                                            else break;
                                        }
                                    }

                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    curVtxIdx = iL[currentVertex]["vtxIdx"];
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    // Return the value stored at the head: {currentVertex}.
                                    cs["status"] = (isHead ? '返还储存在头部的值：<span style="white-space: normal;">{currentVertex}</span>' : '返还储存在尾部的值：<span style="white-space: normal;">{currentVertex}</span>').replace("{currentVertex}", currentVertex);
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);
                                }

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(isHead ? 3 : 9);
                                return true;
                            }

                            /* THIRD MENU: Insert (LL, DLL, minor differences only)/Push (Stack)/Enqueue (Queue, Deque) */

                            this.insertHead = function(v, callback) {
                                var val = parseInt(v);
                                var tempinternalList = deepCopy(iL);

                                // 1. Check whether value is number
                                if (isNaN(val)) {
                                    // Please fill in an Integer.
                                    toastr.warning('请填写一个数字');
                                    
                                    return false;
                                }
                                // 2. No duplicates allowed. Also works if more than one similar value are inserted
                                if (tempinternalList[val] != null) {
                                    // No duplicate vertex allowed!
                                    toastr.error('不能有重复的结点！');
                                   
                                    if (typeof callback == 'function') callback();
                                    return false;
                                }
                                // 3. Check range
                                if (parseInt(val) < valueRange[0] || parseInt(val) > valueRange[1]) {
                                    // Sorry, only values between {range0} and {range1} can be inserted.
                                    toastr.error('抱歉，只能插入值域在<span style="white-space: normal;">&nbsp;{range0} 和 {range1}之间的值&nbsp;</span>'.replace("{range0}", valueRange[0]).replace("{range1}", valueRange[1]));
                                   
                                    return false;
                                }
                                // 4. check size
                                if (activeStatus =="stack") {
                                    if (amountVertex >= maxStackSize) {
                                        // Sorry, the maximum size is {maxSize}.
                                        toastr.error('抱歉，最大的尺寸为<span style="white-space: normal;">{maxSize}</span>'.replace("{maxSize}", maxStackSize));
                                       
                                        return false;
                                    }
                                } else {
                                    if (amountVertex >= maxSize) {
                                        // Sorry, the maximum size is {maxSize}.
                                        toastr.error('抱歉，最大的尺寸为<span style="white-space: normal;">{maxSize}</span>'.replace("{maxSize}", maxSize));                                        
                                        return false;
                                    }
                                }

                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = {},
                                    curVtxIdx;
                                if (amountVertex >= 1) cs = createState(iL);
                                else cs = {};

                                // Begin insertion, first, update internal representation
                                iL[parseInt(val)] = {
                                   "next": null,
                                   "vtxIdx": vertexClassNumberCounter++
                                };

                                // modified this part for linked list insertion
                                var newVtx = parseInt(val);
                                var oldHeadIdx;

                                iL[newVtx]["cx"] = 50;
                                iL[newVtx]["cy"] = 120;

                                // if linked list is empty
                                amountVertex++;
                                if (amountVertex > 1) {
                                    var tempChild = iL["head"];
                                    oldHeadIdx = iL[tempChild]["vtxIdx"];
                                    iL[newVtx]["next"] = tempChild;
                                    iL[tempChild]["prev"] = newVtx;
                                    iL["head"] = newVtx;
                                } else
                                    iL["head"] = newVtx;

                                // Then, draw edge
                                var newVtxIdx = iL[parseInt(val)]["vtxIdx"];

                                if (amountVertex > 1) {
                                    // Vertex vtx = new Vertex(v)
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                    cs["vl"][oldHeadIdx]["extratext"] ="head";
                                    cs["el"][newVtxIdx]["state"] = OBJ_HIDDEN;
                                    if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                        cs["el"][newVtxIdx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                    // Create new vertex to store value {val}.
                                    cs["status"] = '创建一个新的结点来储存值<span style="white-space: normal;">{val}</span>'.replace("{val}", val);
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);

                                    // vtx.next = head
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    var edgeHighlighted = iL[newVtx]["vtxIdx"];
                                    cs["el"][edgeHighlighted]["animateHighlighted"] = true;
                                    cs["el"][edgeHighlighted]["state"] = EDGE_HIGHLIGHTED;
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                    cs["vl"][oldHeadIdx]["extratext"] ="head";
                                    if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                        cs["el"][newVtxIdx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                    // Now, temp.next points to the current head.
                                    cs["status"] = '现在, vtx.next 指向新的头部';
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);

                                    if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                        // if (head != null) head.prev = vtx
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][oldHeadIdx]["extratext"] ="head";
                                        cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                        cs["el"][newVtxIdx + BACK_EDGE_CONST]["state"] = EDGE_HIGHLIGHTED;
                                        cs["el"][newVtxIdx + BACK_EDGE_CONST]["animateHighlighted"] = true;
                                        // (Old) head.prev points to vtx.
                                        cs["status"] = '（旧）head.prev 指向 vtx';
                                        cs["lineNo"] = 3;
                                        stateList.push(cs);
                                    }
                                } else {
                                    // Vertex vtx = new Vertex(v)
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                    // Create new vertex to store value {val}.
                                    // But as head is currently null, temp.next remains null.
                                    cs["status"] = '创建一个新的结点来储存值<span style="white-space: normal;">{val}</span>'.replace("{val}", val) + '<br>但因为头部现在为空，临时的后继仍然为空。';
                                    cs["lineNo"] = [1, 2];
                                    stateList.push(cs);
                                }

                                // head = vtx
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] ="head/vtx";
                                // Now, head points to vtx.
                                cs["status"] = '现在, head 指向 vtx';
                                if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                    cs["lineNo"] = 4;
                                else
                                    cs["lineNo"] = 3;
                                stateList.push(cs);

                                if (amountVertex == 1) {
                                    // tail = head
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][newVtxIdx]["extratext"] ="head/tail/vtx";
                                    // Tail points to head.
                                    cs["status"] = '尾部指针指向头部';
                                    cs["lineNo"] = 3;
                                    stateList.push(cs);
                                }

                                recalculatePosition();
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] ="head" + (amountVertex == 1 ?"/tail" :"") +"/vtx";
                                // Re-layout the Linked List for visualization.
                                // The whole process is O({N}).
                                cs["status"] = '再次铺展链表。<div>整个过程复杂度为 <span style="white-space: normal; font-size: 13px;">O({N}).</span></div>'.replace("{N}","1");
                                cs["lineNo"] = 0;
                                stateList.push(cs);

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(1);
                                return true;
                            }

                            this.insertTail = function(v, callback) {
                                if (amountVertex == 0) return this.insertHead(v, callback);

                                var val = parseInt(v);
                                var tempinternalList = deepCopy(iL); // Use this to simulate internal insertion

                                // 1. Check whether value is number
                                if (isNaN(val)) {
                                    // Please fill in an Integer.
                                   toastr.error('请填写一个数字');
                                    if (typeof callback == 'function') callback();
                                    return false;
                                }
                                // 2. No duplicates allowed. Also works if more than one similar value are inserted
                                if (tempinternalList[val] != null) {
                                    // No duplicate vertex allowed!
                                   toastr.error('不能有重复的结点！');
                                    if (typeof callback == 'function') callback();
                                    return false;
                                }
                                // 3. Check range
                                if (parseInt(val) < valueRange[0] || parseInt(val) > valueRange[1]) {
                                    // Sorry, only values between {range0} and {range1} can be inserted.
                                   toastr.error('抱歉，只能插入值域在<span style="white-space: normal;">&nbsp;{range0} 和 {range1}之间的值&nbsp;</span>'.replace("{range0}", valueRange[0]).replace("{range1}", valueRange[1]));
                                    if (typeof callback == 'function') callback();
                                    return false;
                                }
                                // 4. check size
                                if (amountVertex >= maxSize) {
                                    // Sorry, the maximum size is {maxSize}.
                                   toastr.error('抱歉，最大的尺寸为<span style="white-space: normal;">{maxSize}</span>'.replace("{maxSize}", maxSize));
                                    if (typeof callback == 'function') callback();
                                    return false;
                                }

                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = {},
                                    curVtxIdx;

                                // Find prev
                                while (currentVertex != val && currentVertex != null) {
                                    var nextVertex;
                                    nextVertex = iL[currentVertex]["next"];
                                    if (nextVertex == null) break;
                                    else currentVertex = nextVertex;
                                }

                                // Begin insertion, first, update internal representation
                                var newVtx = parseInt(val);
                                var oldTailIdx = iL[currentVertex]["vtxIdx"];

                                iL[parseInt(val)] = {
                                   "next": null,
                                   "vtxIdx": vertexClassNumberCounter++
                                };

                                if (currentVertex != null) {
                                    iL[parseInt(val)]["prev"] = currentVertex;
                                    iL[currentVertex]["next"] = parseInt(val);
                                } else {
                                    iL[parseInt(val)]["prev"] = null;
                                    iL["head"] = parseInt(val);
                                }

                                amountVertex++;
                                recalculatePosition();

                                var newVtxIdx = iL[parseInt(val)]["vtxIdx"];
                                curVtxIdx = iL[currentVertex]["vtxIdx"];

                                // Vertex vtx = new vertex(v)
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                cs["vl"][oldTailIdx]["extratext"] ="tail";
                                cs["el"][curVtxIdx]["state"] = OBJ_HIDDEN;
                                if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                    cs["el"][curVtxIdx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                // Create new vertex to store value {val}.
                                cs["status"] = '创建一个新的结点来储存值<span style="white-space: normal;">{val}</span>'.replace("{val}", val);
                                cs["lineNo"] = 1;
                                stateList.push(cs);

                                // tail.next = vtx
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][curVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                cs["vl"][oldTailIdx]["extratext"] ="tail";
                                cs["el"][curVtxIdx]["state"] = EDGE_TRAVERSED;
                                cs["el"][curVtxIdx]["animateHighlighted"] = true;
                                if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                    cs["el"][curVtxIdx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                // Now vtx.next points to new vertex.
                                cs["status"] = '现在 临时的后继指针指向新结点';
                                cs["lineNo"] = 2;
                                stateList.push(cs);

                                if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][curVtxIdx]["extratext"] ="tail";
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                    cs["el"][curVtxIdx + BACK_EDGE_CONST]["state"] = EDGE_HIGHLIGHTED;
                                    cs["el"][curVtxIdx + BACK_EDGE_CONST]["animateHighlighted"] = true;
                                    // Update prev pointer of the new vertex to point back to the (old) tail.
                                    cs["status"] = '更新新结点的pre 指针为指向（旧）尾部的指针';
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);
                                }

                                // tail = vtx
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] ="tail/vtx";
                                // Now, tail points to the new vertex too.
                                // The whole operation is O(1) if we maintain the tail pointer.
                                cs["status"] = '现在，尾部指针也指向新的结点。<div>如果我们保留尾部指针，整个操作的复杂度为O(1)</div>';
                                cs["lineNo"] = 3;
                                stateList.push(cs);

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(2);
                                return true;
                            }

                            this.insertKth = function(index, v, callback) {
                                // index checking start
                                if (isNaN(index)) {
                                    // Please fill in an Integer.
                                   toastr.error('请填写一个数字');
                                    return false;
                                }
                                if ((index < 1) || (index > amountVertex)) {
                                    // Please enter a valid index between [1..{limit}].
                                   toastr.error('请在<span style="white-space: normal;">&nbsp;[0..{limit}] 范围内</span>输入一个有效的下标'.replace("{limit}", Math.max(1, amountVertex - 1)));
                                    return false;
                                }

                                // check if it is insertion at index 0/N i.e. insert head/tail, respectively (will no longer be used?)
                                if (index == 0) return this.insertHead(v);
                                if (index == amountVertex) return this.insertTail(v);

                                var val = parseInt(v);
                                var tempinternalList = deepCopy(iL); // Use this to simulate internal insertion

                                // 1. Check whether value is number
                                if (isNaN(val)) {
                                    // Please fill in an Integer.
                                   toastr.error('请填写一个数字');
                                    return false;
                                }
                                // 2. No duplicates allowed. Also works if more than one similar value are inserted
                                if (tempinternalList[val] != null) {
                                    // No duplicate vertex allowed!
                                   toastr.error('不能有重复的结点！');
                                    return false;
                                }
                                // 3. Check range
                                if (parseInt(val) < valueRange[0] || parseInt(val) > valueRange[1]) {
                                    // Sorry, only values between {range0} and {range1} can be inserted.
                                   toastr.error('抱歉，只能插入值域在<span style="white-space: normal;">&nbsp;{range0} 和 {range1}之间的值&nbsp;</span>'.replace("{range0}", valueRange[0]).replace("{range1}", valueRange[1]));
                                    return false;
                                }
                                // 4. check size
                                if (amountVertex >= maxSize) {
                                    // Sorry, the maximum size is {maxSize}.
                                   toastr.error('抱歉，最大的尺寸为<span style="white-space: normal;">{maxSize}</span>'.replace("{maxSize}", maxSize));
                                    return false;
                                }

                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = {};
                                var temp1Idx, temp2Idx, newVtxIdx;

                                // Vertex prev = head
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                temp1Idx = iL[currentVertex]["vtxIdx"];
                                cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][temp1Idx]["extratext"] ="0/head/pre";
                                vertexTraversed[currentVertex] = true;
                                // Set prev to head.
                                cs["status"] = '设定临时指针 temp1 为 头部';
                                cs["lineNo"] = 1;
                                stateList.push(cs);

                                // Find prev
                                // for (k = 0; k < i; k++)
                                var i = 0;
                                for (var k = 0; k < index - 1; k++) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    temp1Idx = iL[currentVertex]["vtxIdx"];
                                    cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                    vertexTraversed[currentVertex] = true;
                                    // Increment k, index specified has not been reached.
                                    // k is now: {k}.
                                    cs["status"] = '递减k，特定的下标还没有达到。<div>k现在是：<span style="white-space: normal; font-size: 13px;">{k}</span></div>'.replace("{k}", k);
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);

                                    var nextVertex;
                                    nextVertex = iL[currentVertex]["next"];

                                    if (nextVertex == null) break;
                                    else currentVertex = nextVertex;

                                    // pre = pre.next
                                    curVtx = iL[currentVertex]["prev"];
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    var edgeHighlighted = iL[curVtx]["vtxIdx"];
                                    edgeTraversed[edgeHighlighted] = true;
                                    cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                    cs["el"][edgeHighlighted]["animateHighlighted"] = true;
                                    cs["el"][edgeHighlighted]["state"] = EDGE_TRAVERSED;
                                    // We set prev to the next vertex.
                                    cs["status"] = '将prev移向下一节点';
                                    cs["lineNo"] = 3;
                                    stateList.push(cs);

                                    i++;
                                }

                                if (currentVertex != null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    temp1Idx = iL[currentVertex]["vtxIdx"];
                                    cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                    vertexTraversed[currentVertex] = true;
                                    // We have found the insertion point.
                                    // We continue the next insertion step.
                                    cs["status"] = '我们找到了插入点。<br><div>我们继续下一步插入的操作</div>';
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);
                                }

                                // Begin insertion, first, update internal representation
                                // Vertex aft = pre.next
                                var temp2Vertex = iL[currentVertex]["next"];
                                temp2Idx = iL[temp2Vertex]["vtxIdx"];
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                cs["vl"][temp2Idx]["state"] = VERTEX_BLUE_FILL;
                                cs["vl"][temp2Idx]["extratext"] = (i + 1) + (i + 1 == 0 ?"/head" : (iL[temp2Vertex]["next"] == null ?"/tail" :"")) +"/aft";
                                cs["el"][temp1Idx]["state"] = EDGE_TRAVERSED;
                                cs["el"][temp1Idx]["animateHighlighted"] = true;
                                edgeTraversed[temp1Idx] = true;
                                // The specified index is found.
                                // pre is before the insertion point and aft is the insertion point.
                                cs["status"] = '指定的';
                                cs["lineNo"] = 4;
                                stateList.push(cs);

                                iL[parseInt(val)] = {
                                   "next": null,
                                   "vtxIdx": vertexClassNumberCounter++
                                };
                                amountVertex++;
                                //modified this part for linked list insertion
                                var newVtx = parseInt(val);
                                newVtxIdx = iL[parseInt(val)]["vtxIdx"];
                                var tempChild;

                                iL[newVtx]["cx"] = iL[temp2Vertex]["cx"];
                                iL[newVtx]["cy"] = iL[temp2Vertex]["cy"] + 70;

                                // vertex vtx = new Vertex(v)
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                cs["vl"][temp2Idx]["state"] = VERTEX_BLUE_FILL;
                                cs["vl"][temp2Idx]["extratext"] = (i + 1) + (i + 1 == 0 ?"/head" : (iL[temp2Vertex]["next"] == null ?"/tail" :"")) +"/aft";
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                // Create new vertex to store value {val}.
                                cs["status"] = '创建一个新的结点来储存值<span style="white-space: normal;">{val}</span>'.replace("{val}", val);
                                cs["lineNo"] = 5;
                                stateList.push(cs);
                                edgeTraversed[newVtxIdx] = true;

                                // RELINK THE POINTERs
                                iL[newVtx]["next"] = temp2Vertex;
                                iL[temp2Vertex]["prev"] = newVtx;

                                // vtx.next = aft
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                cs["vl"][temp2Idx]["state"] = VERTEX_BLUE_FILL;
                                cs["vl"][temp2Idx]["extratext"] = (i + 1) + (i + 1 == 0 ?"/head" : (iL[temp2Vertex]["next"] == null ?"/tail" :"")) +"/aft";
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                cs["el"][temp1Idx]["state"] = EDGE_TRAVERSED;
                                cs["el"][newVtxIdx]["state"] = EDGE_GREEN;
                                cs["el"][newVtxIdx]["animateHighlighted"] = true;
                                if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                    cs["el"][newVtxIdx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                // v.next points to aft.
                                cs["status"] = '<span style="white-space: normal;">vtx.next 指向 aft.</span>';
                                cs["lineNo"] = 6;
                                stateList.push(cs);

                                // aft.prev = v (for DLL and deque)
                                if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                    cs["vl"][temp2Idx]["state"] = VERTEX_BLUE_FILL;
                                    cs["vl"][temp2Idx]["extratext"] = (i + 1) + (i + 1 == 0 ?"/head" : (iL[temp2Vertex]["next"] == null ?"/tail" :"")) +"/aft";
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][newVtxIdx]["extratext"] ="vtx";
                                    cs["el"][temp1Idx]["state"] = EDGE_TRAVERSED;
                                    cs["el"][newVtxIdx]["state"] = EDGE_GREEN;
                                    cs["el"][newVtxIdx + BACK_EDGE_CONST]["state"] = EDGE_GREEN;
                                    cs["el"][temp1Idx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                    // aft.prev points to vtx.
                                    cs["status"] = '<span style="white-space: normal;">aft.prev 指向 vtx.</span>';
                                    cs["lineNo"] = 6;
                                    stateList.push(cs);
                                }

                                iL[currentVertex]["next"] = newVtx;
                                iL[newVtx]["prev"] = currentVertex;

                                // pre.next = vtx
                                cs = createState(iL, vertexTraversed, edgeTraversed);
                                cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                cs["vl"][temp2Idx]["state"] = VERTEX_BLUE_FILL;
                                cs["vl"][temp2Idx]["extratext"] = (i + 2) + (i + 1 == 0 ?"/head" : (iL[temp2Vertex]["next"] == null ?"/tail" :"")) +"/aft";
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] = (i + 1) +"/vtx";
                                cs["el"][newVtxIdx]["state"] = EDGE_GREEN;
                                cs["el"][temp1Idx]["state"] = EDGE_TRAVERSED;
                                if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                    cs["el"][temp1Idx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                // pre.next points to vtx.
                                cs["status"] = 'pre.next 指向  vtx';
                                cs["lineNo"] = 7;
                                stateList.push(cs);

                                // vtx.prev = pre
                                if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][temp1Idx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][temp1Idx]["extratext"] = i + (i == 0 ?"/head" : (iL[currentVertex]["next"] == null ?"/tail" :"")) +"/pre";
                                    cs["vl"][temp2Idx]["state"] = VERTEX_BLUE_FILL;
                                    cs["vl"][temp2Idx]["extratext"] = (i + 2) + (i + 1 == 0 ?"/head" : (iL[temp2Vertex]["next"] == null ?"/tail" :"")) +"/aft";
                                    cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][newVtxIdx]["extratext"] = temp2Idx +"/vtx";
                                    cs["el"][temp1Idx]["state"] = EDGE_TRAVERSED;
                                    cs["el"][temp1Idx + BACK_EDGE_CONST]["state"] = EDGE_TRAVERSED;
                                    // vtx.prev points to pre.
                                    cs["status"] = '<span style="white-space: normal;">vtx.prev 指向 to pre.</span>';
                                    cs["lineNo"] = 7;
                                    stateList.push(cs);
                                }

                                recalculatePosition();
                                cs = createState(iL, {}, {});
                                cs["vl"][newVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                cs["vl"][newVtxIdx]["extratext"] = (i + 1) +"/vtx";
                                // Re-layout the Linked List for visualization.
                                // The whole process is O({N}).
                                cs["status"] = '再次铺展链表。<div>整个过程复杂度为 <span style="white-space: normal; font-size: 13px;">O({N}).</span></div>'.replace("{N}","N");
                                cs["lineNo"] = 0;
                                stateList.push(cs);

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(0);
                                return true;
                            }

                            /* FOURTH MENU: Remove */

                            this.removeHead = function(callback) {
                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = {},
                                    curVtxIdx;

                                if (currentVertex == null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    // The Linked List is already empty.
                                    // No action is performed.
                                    cs["status"] = '链表已经空了。<div>无操作。</div>';
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);
                                } else {
                                    if (iL[currentVertex]["next"] == null) { // head has no next vertex
                                        // temp = head
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        // The head is the only vertex in this List.
                                        cs["status"] = '头部是这个列表中唯一一个结点。';
                                        cs["lineNo"] = 2;
                                        stateList.push(cs);

                                        // head = head.next
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        // Head points to next (which is null).
                                        cs["status"] = '头部指针指向下一个(即为空)。';
                                        cs["lineNo"] = 3;
                                        stateList.push(cs);

                                        curVtxIdx = iL[currentVertex]["vtxIdx"];

                                        // delete temp
                                        iL["head"] = null;
                                        delete iL[currentVertex];
                                        delete vertexTraversed[currentVertex];
                                        delete edgeTraversed[curVtxIdx];

                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        // Remove head vertex.
                                        // We now have an empty List.
                                        cs["status"] = '移除前端结点。<div>我们现在有一个空的列表。</div>';
                                        cs["lineNo"] = 4;
                                        stateList.push(cs);
                                    } else { // head has next vertex
                                        // temp = head
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][curVtxIdx]["extratext"] ="head/temp";
                                        // The head has a next vertex.
                                        cs["status"] = '头部指针已有下一个结点。';
                                        cs["lineNo"] = 2;
                                        stateList.push(cs);

                                        var rightChildVertex = iL[currentVertex]["next"];
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        nextVtxIdx = iL[rightChildVertex]["vtxIdx"];

                                        // head = head.next
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][curVtxIdx]["extratext"] ="temp";
                                        cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                        cs["vl"][nextVtxIdx]["extratext"] ="head";
                                        cs["el"][curVtxIdx]["state"] = EDGE_GREEN;
                                        cs["el"][curVtxIdx]["animateHighlighted"] = true;
                                        // head points to the next vertex.
                                        cs["status"] = '头部指针指向下一个结点。';
                                        cs["lineNo"] = 3;
                                        stateList.push(cs);

                                        iL["head"] = rightChildVertex;
                                        iL[rightChildVertex]["prev"] = null;

                                        // delete temp
                                        delete iL[currentVertex];
                                        delete vertexTraversed[currentVertex];
                                        delete edgeTraversed[curVtxIdx];
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                        // Delete temp = (previous) head.
                                        cs["status"] = '删除 临时 = (之前的) 头部。';
                                        cs["lineNo"] = 4;
                                        stateList.push(cs);

                                        if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                            // head.prev = null
                                            cs = createState(iL, vertexTraversed, edgeTraversed);
                                            cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                            // Set head.prev to null for consistency purpose.
                                            cs["status"] = '为了一致性，将头部的前继设置为空。';
                                            cs["lineNo"] = 5;
                                            stateList.push(cs);
                                        }

                                        // relayout
                                        amountVertex--;
                                        recalculatePosition(); // this line triggers some D3.js errors although OK? find the root cause?
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                        if (amountVertex == 1) cs["vl"][nextVtxIdx]["extratext"] ="head/tail";
                                        // Re-layout the Linked List for visualization.
                                        // The whole process is O({N}).
                                        cs["status"] = '再次铺展链表。<div>整个过程复杂度为 <span style="white-space: normal; font-size: 13px;">O({N}).</span></div>'.replace("{N}","1");
                                        stateList.push(cs);
                                    }
                                }

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(5);
                                return true;
                            }

                            this.removeTail = function(callback) {
                                if (amountVertex == 1) return this.removeHead(callback); // special case

                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = {},
                                    curVtxIdx;

                                if (currentVertex == null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    // The Linked List is already empty.
                                    // No action is performed.
                                    cs["status"] = '链表已经空了。<div>无操作。</div>';
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);
                                } else {
                                    var nextVertex = iL[currentVertex]["next"],
                                        nextVtxIdx;

                                    // Vertex pre = head
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    curVtxIdx = iL[currentVertex]["vtxIdx"];
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][curVtxIdx]["extratext"] ="head/pre";
                                    // Set up pre pointer.
                                    // pre will eventually point to the last vertex before tail.
                                    cs["status"] = '建立 pre 指针。<div>pre 将在指向尾部前最终指向最后一个结点。</div>';
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);

                                    // temp = head.next
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    curVtxIdx = iL[currentVertex]["vtxIdx"];
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][curVtxIdx]["extratext"] ="head/pre";
                                    nextVtxIdx = iL[nextVertex]["vtxIdx"];
                                    cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][nextVtxIdx]["extratext"] = (iL[nextVertex]["next"] == null ?"tail/" :"") +"temp";
                                    cs["el"][curVtxIdx]["animateHighlighted"] = true;
                                    cs["el"][curVtxIdx]["state"] = EDGE_TRAVERSED;
                                    // Set up temp pointer.
                                    // temp will eventually point to the current tail.
                                    cs["status"] = '建立临时指针。<div>指针最终会指向现有的尾部。</div>';
                                    cs["lineNo"] = 3;
                                    stateList.push(cs);

                                    // Find vertex
                                    var i = 0;
                                    while (true) {
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][curVtxIdx]["extratext"] = (i == 0 ?"head/" :"") +"pre";
                                        nextVtxIdx = iL[nextVertex]["vtxIdx"];
                                        cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                        cs["vl"][nextVtxIdx]["extratext"] = (iL[nextVertex]["next"] == null ?"tail/" :"") +"temp";
                                        vertexTraversed[currentVertex] = true;
                                        // Check if temp.next is null.
                                        cs["status"] = '检查临时的后继是否为空。';
                                        cs["lineNo"] = 4;
                                        stateList.push(cs);

                                        if (iL[nextVertex]["next"] != null) {
                                            nextVertex = iL[nextVertex]["next"];
                                            currentVertex = iL[currentVertex]["next"];
                                            i++;
                                        } else
                                            break;

                                        // pre = pre.next, temp = temp.next
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        curVtxIdx = iL[currentVertex]["vtxIdx"];
                                        cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][curVtxIdx]["extratext"] = (i == 0 ?"head/" :"") +"pre";
                                        nextVtxIdx = iL[nextVertex]["vtxIdx"];
                                        cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                        cs["vl"][nextVtxIdx]["extratext"] = (iL[nextVertex]["next"] == null ?"tail/" :"") +"temp";
                                        vertexTraversed[currentVertex] = true;
                                        curVtx = iL[currentVertex]["prev"];
                                        var edgeHighlighted = iL[curVtx]["vtxIdx"];
                                        cs["el"][edgeHighlighted]["animateHighlighted"] = true;
                                        cs["el"][edgeHighlighted]["state"] = EDGE_TRAVERSED;
                                        edgeTraversed[edgeHighlighted] = true;
                                        var edgeHighlighted2 = iL[currentVertex]["vtxIdx"];
                                        cs["el"][edgeHighlighted2]["animateHighlighted"] = true;
                                        cs["el"][edgeHighlighted2]["state"] = EDGE_GREEN;
                                        // It is not null.
                                        // So both pre and temp pointers advance to their next vertex.
                                        cs["status"] = '它不是空。<div>所以pre和临时的指针都移至他们下一个结点。</div>';
                                        cs["lineNo"] = 5;
                                        stateList.push(cs);
                                    }

                                    // pre.next = null
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    curVtxIdx = iL[currentVertex]["vtxIdx"];
                                    nextVtxIdx = iL[nextVertex]["vtxIdx"];
                                    cs["el"][curVtxIdx]["state"] = OBJ_HIDDEN;
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][curVtxIdx]["extratext"] = (i == 0 ?"head/" :"") +"pre";
                                    nextVtxIdx = iL[nextVertex]["vtxIdx"];
                                    cs["vl"][nextVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][nextVtxIdx]["extratext"] ="tail/temp";
                                    vertexTraversed[currentVertex] = true;
                                    // It is null.
                                    // So set the next of pre (the new tail) to null.
                                    cs["status"] = '它为空。<div>所以我们将pre的后继（新的尾部）设为空。</div>';
                                    cs["lineNo"] = 6;
                                    stateList.push(cs);

                                    var curVtx = iL[nextVertex]["prev"];
                                    if (curVtx != null) iL[curVtx]["next"] = null;
                                    else iL["head"] = null;

                                    // delete temp, tail = pre
                                    delete iL[nextVertex];
                                    delete vertexTraversed[nextVertex];
                                    delete edgeTraversed[nextVtxIdx];

                                    amountVertex--;

                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    if (amountVertex == 1) cs["vl"][curVtxIdx]["extratext"] ="head/tail";
                                    // Delete temp (the previous tail) then update the tail pointer to prev (the current tail). The whole process is O(N) just to find the pre pointer.
                                    cs["status"] = '删除临时（原来的尾部）然后将尾部的指针设置为pre（现在的尾部）。<div>整个找到pre指针过程的复杂度为O(N) 。</div>';
                                    cs["lineNo"] = 7;
                                    stateList.push(cs);
                                }

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(6);
                                return true;
                            }

                            this.removeTailDLL = function(callback) {
                                if (amountVertex == 1) return this.removeHead(callback);

                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    currentVertex = iL["head"],
                                    cs = {};

                                if (currentVertex == null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    // The Linked List is already empty.
                                    // No action is performed.
                                    cs["status"] = '链表已经空了。<div>无操作。</div>';
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);
                                } else {
                                    var nextVertex = iL[currentVertex]["next"];
                                    var curVtxIdx, nextVtxIdx;

                                    // Find tail vertex
                                    while (true) {
                                        if (iL[nextVertex]["next"] != null) {
                                            nextVertex = iL[nextVertex]["next"];
                                            currentVertex = iL[currentVertex]["next"];
                                        } else
                                            break;
                                    }

                                    curVtxIdx = iL[currentVertex]["vtxIdx"];
                                    nextVtxIdx = iL[nextVertex]["vtxIdx"];

                                    // temp = tail
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][nextVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][nextVtxIdx]["extratext"] ="tail/temp";
                                    // Set temp to (old) tail.
                                    cs["status"] = '将临时设置为（原来的）尾部。';
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);

                                    // tail = tail.prev
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][nextVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][nextVtxIdx]["extratext"] ="temp";
                                    cs["el"][curVtxIdx + BACK_EDGE_CONST]["state"] = EDGE_HIGHLIGHTED;
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][curVtxIdx]["extratext"] ="tail";
                                    // Set tail to tail.prev
                                    cs["status"] = '将尾部设置为尾部的前继';
                                    cs["lineNo"] = 3;
                                    stateList.push(cs);

                                    // tail.next = null
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][curVtxIdx]["extratext"] ="tail";
                                    cs["vl"][nextVtxIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][nextVtxIdx]["extratext"] ="temp";
                                    cs["el"][curVtxIdx]["state"] = OBJ_HIDDEN;
                                    vertexTraversed[currentVertex] = true;
                                    // Set the next of (new) tail to null.
                                    cs["status"] = '将(新的) 尾部的后继设置为空。';
                                    cs["lineNo"] = 4;
                                    stateList.push(cs);

                                    var curVtx = iL[nextVertex]["prev"];
                                    if (curVtx != null) iL[curVtx]["next"] = null;
                                    else iL["head"] = null;

                                    delete iL[nextVertex];
                                    delete vertexTraversed[nextVertex];
                                    delete edgeTraversed[nextVtxIdx];

                                    amountVertex--;

                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][curVtxIdx]["state"] = VERTEX_GREEN_FILL;
                                    if (amountVertex == 1) cs["vl"][curVtxIdx]["extratext"] ="head/tail";
                                    // Delete temp.
                                    // The whole operations is just O(1) as we can access (old) tail.prev.
                                    cs["status"] = '删除临时。<div>整个操作的复杂度为O(1) 因为我们可以使用(原来的) 尾部的前继。</div>';
                                    cs["lineNo"] = 5;
                                    stateList.push(cs);
                                }

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(8);
                                return true;
                            }

                            this.removeKth = function(v, callback) {
                                var index = parseInt(v);

                                // Check whether value is number
                                if (isNaN(index)) {
                                     toastr.error('请填写一个数字');
                                    return false;
                                }
                                if (amountVertex < 3) {
                                    // This operation only works for N bigger than 2.
                                     toastr.error('这个操作仅限于N&gt;2');
                                    return false;
                                }
                                if ((index < 1) || (index >= amountVertex - 1)) {
                                    // Please enter a valid index between [1..{limit}].
                                     toastr.error('请在<span style="white-space: normal;">&nbsp;[0..{limit}] 范围内</span>输入一个有效的下标'.replace("{limit}", Math.max(1, amountVertex - 2)));
                                    return false;
                                }

                                if (index == 0) return this.removeHead(); // not going to be executable
                                if (index == amountVertex - 1) {
                                    if (this.getActiveStatus() =="doublylist") return this.removeTailDLL();
                                    else return this.removeTail();
                                }

                                var stateList = [],
                                    vertexTraversed = {},
                                    edgeTraversed = {},
                                    prevVtx = iL["head"],
                                    delVtx, afterVtx, cs = {};
                                var prevIdx, delIdx, afterIdx;

                                if (prevVtx == null) {
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    // The Linked List is already empty.
                                    // No action is performed.
                                    cs["status"] = '链表已经空了。<div>无操作。</div>';
                                    cs["lineNo"] = 1;
                                    stateList.push(cs);
                                } else {
                                    // Vertex pre = head
                                    prevIdx = iL[prevVtx]["vtxIdx"];
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][prevIdx]["extratext"] ="0/head/pre";
                                    // Set prev to head.
                                    // Pointer prev will stop at one vertex before the deleted vertex.
                                    cs["status"] = '将 pre 指向头部。<div>指针pre会在已删除结点的前一个结点停下。</div>';
                                    cs["lineNo"] = 2;
                                    stateList.push(cs);

                                    // Find vertex
                                    for (i = 0; i < index - 1; i++) {
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][prevIdx]["extratext"] = i + (i == 0 ?"/head" :"") +"/pre";
                                        vertexTraversed[prevVtx] = true;
                                        // Index specified has not been reached.
                                        // k = {k}.
                                        cs["status"] = '指定的索引还未达到。<div>k={i} </div>'.replace("{k}", i);
                                        cs["lineNo"] = 3;
                                        stateList.push(cs);

                                        // important assignment
                                        var edgeHighlighted = iL[prevVtx]["vtxIdx"]; // before moving
                                        prevVtx = iL[prevVtx]["next"];
                                        prevIdx = iL[prevVtx]["vtxIdx"];

                                        // pre = pre.next
                                        cs = createState(iL, vertexTraversed, edgeTraversed);
                                        cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                        cs["vl"][prevIdx]["extratext"] = (i + 1) +"/pre";
                                        edgeTraversed[edgeHighlighted] = true;
                                        cs["el"][edgeHighlighted]["animateHighlighted"] = true;
                                        cs["el"][edgeHighlighted]["state"] = EDGE_TRAVERSED;
                                        // Pointer prev advances to the next vertex.
                                        cs["status"] = '指针 pre 移至下一个结点。';
                                        cs["lineNo"] = 4;
                                        stateList.push(cs);
                                    }

                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][prevIdx]["extratext"] = i +"/pre";
                                    vertexTraversed[prevVtx] = true;
                                    // k is 0, prev now points to one vertex behind the vertex to-be-deleted.
                                    // We stop searching and continue with the removal.
                                    cs["status"] = 'k为0，pre 现在指向将要被删除的结点。<div>我们停止搜找，继续移除的步骤。</div>';
                                    cs["lineNo"] = 3;
                                    stateList.push(cs);

                                    var delVertex = iL[prevVtx]["next"];
                                    delIdx = iL[delVertex]["vtxIdx"];
                                    var afterVertex = iL[delVertex]["next"];
                                    afterIdx = iL[afterVertex]["vtxIdx"];

                                    // Vertex del = prev.next
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][prevIdx]["extratext"] = i +"/pre";
                                    cs["vl"][delIdx]["state"] = VERTEX_RED_FILL;
                                    cs["vl"][delIdx]["extratext"] = (i + 1) +"/del";
                                    cs["vl"][afterIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][afterIdx]["extratext"] = (i + 2) +"/aft";
                                    edgeTraversed[prevIdx] = edgeTraversed[delIdx] = true;
                                    cs["el"][prevIdx]["animateHighlighted"] = cs["el"][delIdx]["animateHighlighted"] = true;
                                    cs["el"][prevIdx]["state"] = EDGE_HIGHLIGHTED;
                                    cs["el"][delIdx]["state"] = EDGE_RED;
                                    if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                        cs["el"][prevIdx + BACK_EDGE_CONST]["state"] = EDGE_HIGHLIGHTED;
                                        cs["el"][delIdx + BACK_EDGE_CONST]["state"] = EDGE_RED;
                                    }
                                    vertexTraversed[prevVtx] = true;
                                    // We store reference to the vertex to-be-deleted.
                                    // We also store reference to the vertex after the to-be-deleted vertex.
                                    cs["status"] = '我们储存将要被删除结点的引用。<div>我们也储存将要被删除结点之后的结点的引用。</div>';
                                    cs["lineNo"] = 5;
                                    stateList.push(cs);

                                    // prev.next = after, after.prev = prev (for DLL and deque)
                                    iL[delVertex]["cy"] = 50 + iL[delVertex]["cy"];
                                    iL[prevVtx]["next"] = afterVertex;
                                    iL[afterVertex]["prev"] = prevVtx;

                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][prevIdx]["extratext"] = i +"/pre";
                                    cs["vl"][delIdx]["state"] = VERTEX_RED_FILL;
                                    cs["vl"][delIdx]["extratext"] ="del";
                                    cs["vl"][afterIdx]["state"] = VERTEX_GREEN_FILL;
                                    cs["vl"][afterIdx]["extratext"] = (i + 1) +"/aft";
                                    cs["el"][prevIdx]["animateHighlighted"] = true;
                                    cs["el"][prevIdx]["state"] = EDGE_HIGHLIGHTED;
                                    if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                        cs["el"][prevIdx + BACK_EDGE_CONST]["state"] = EDGE_HIGHLIGHTED;
                                        cs["el"][delIdx + BACK_EDGE_CONST]["state"] = OBJ_HIDDEN;
                                    }
                                    // We connect the vertex behind the vertex to-be-deleted (pointer prev) with the next vertex after the vertex to-be-deleted (pointer after).
                                    cs["status"] = '我们把将要被删除结点(指针 pre) 和 它之后的结点(指针 after) 连接起来。';
                                    cs["lineNo"] = 6;
                                    stateList.push(cs);

                                    // delete temp
                                    delete iL[delVertex];
                                    delete vertexTraversed[delVertex];
                                    delete edgeTraversed[delIdx];
                                    cs = createState(iL, vertexTraversed, edgeTraversed);
                                    cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][afterIdx]["state"] = VERTEX_GREEN_FILL;
                                    // Now we delete this vertex.
                                    cs["status"] = '现在我们删除这个结点';
                                    cs["lineNo"] = 7;
                                    stateList.push(cs);
                                    amountVertex--;

                                    // relayout list
                                    recalculatePosition();
                                    cs = createState(iL, {}, {});
                                    cs["vl"][prevIdx]["state"] = VERTEX_HIGHLIGHTED;
                                    cs["vl"][afterIdx]["state"] = VERTEX_GREEN_FILL;
                                    if (amountVertex == 1) cs["vl"][afterIdx]["extratext"] ="head/tail";
                                    // Re-layout the Linked List for visualization.
                                    // The whole process is O({N}).
                                    cs["status"] = '再次铺展链表。<div>整个过程复杂度为 <span style="white-space: normal; font-size: 13px;">O({N}).</span></div>'.replace("{N}","N");
                                    stateList.push(cs);
                                }

                                graphWidget.startAnimation(stateList, callback);
                                populatePseudocode(7);
                                return true;
                            }

                            function init(initArr) {
                                amountVertex = 0;
                                clearScreen();

                                for (var i = 0; i < initArr.length; i++) {
                                    var curVtx = iL["head"];
                                    var newVtx = parseInt(initArr[i]);

                                    if (curVtx == null) {
                                        iL["head"] = parseInt(newVtx);
                                        iL[newVtx] = {
                                           "prev": null,
                                           "next": null,
                                           "vtxIdx": amountVertex
                                        };
                                    } else {
                                        while (true) { // go to tail
                                            if (iL[curVtx]["next"] == null) break;
                                            curVtx = iL[curVtx]["next"];
                                        }
                                        iL[curVtx]["next"] = newVtx;
                                        iL[newVtx] = {
                                           "prev": curVtx,
                                           "next": null,
                                           "vtxIdx": amountVertex
                                        }
                                    }

                                    amountVertex++;
                                }

                                recalculatePosition();

                                for (key in iL) {
                                    if (key =="head") continue;
                                    graphWidget.addVertex(iL[key]["cx"], iL[key]["cy"], key, iL[key]["vtxIdx"], true, (iL["head"] == key ?"head" : (iL[key]["next"] == null ?"tail" :""))); // iL[key]["vtxIdx"] + 
                                }

                                for (key in iL) {
                                    if (key =="head") continue;
                                    if (key == iL["head"]) continue;
                                    var curVtx = iL[key]["prev"];

                                    graphWidget.addEdge(iL[curVtx]["vtxIdx"], iL[key]["vtxIdx"], iL[curVtx]["vtxIdx"], EDGE_TYPE_DE, 1, true);
                                    if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                        graphWidget.addEdge(iL[key]["vtxIdx"], iL[curVtx]["vtxIdx"], iL[curVtx]["vtxIdx"] + BACK_EDGE_CONST, EDGE_TYPE_DE, 1, true);
                                }
                            }

                            function clearScreen() {
                                var key;

                                for (key in iL) {
                                    if (key =="head") continue;
                                    graphWidget.removeEdge(iL[key]["vtxIdx"] + BACK_EDGE_CONST);
                                    graphWidget.removeEdge(iL[key]["vtxIdx"]);
                                }

                                for (key in iL) {
                                    if (key =="head") continue;
                                    graphWidget.removeVertex(iL[key]["vtxIdx"]);
                                }

                                iL = {};
                                iL["head"] = null;
                                amountVertex = 0;
                            }

                            this.getN = function() {
                                return amountVertex;
                            }

                            /*
                             * iLObject: a JS object with the same structure of iL. This means the List doen't have to be the List stored in this class
                             * vertexTraversed: JS object with the vertexes of the List which are to be marked as traversed as the key
                             * edgeTraversed: JS object with the edges of the List which are to be marked as traversed as the key
                             */

                            function createState(iLObject, vertexTraversed, edgeTraversed) {
                                if (vertexTraversed == null || vertexTraversed == undefined || !(vertexTraversed instanceof Object))
                                    vertexTraversed = {};
                                if (edgeTraversed == null || edgeTraversed == undefined || !(edgeTraversed instanceof Object))
                                    edgeTraversed = {};

                                var state = {
                                   "vl": {},
                                   "el": {}
                                };
                                var key;

                                for (key in iLObject) {
                                    if (key =="head") continue;

                                    idx = iLObject[key]["vtxIdx"];

                                    state["vl"][idx] = {};
                                    state["vl"][idx]["cx"] = iLObject[key]["cx"];
                                    state["vl"][idx]["cy"] = iLObject[key]["cy"];
                                    state["vl"][idx]["text"] = key;
                                    state["vl"][idx]["state"] = VERTEX_DEFAULT;

                                    if (iLObject[key]["next"] == null) continue;

                                    parentChildEdgeId = iLObject[key]["vtxIdx"];

                                    state["el"][parentChildEdgeId] = {};

                                    state["el"][parentChildEdgeId]["vertexA"] = iLObject[key]["vtxIdx"];
                                    state["el"][parentChildEdgeId]["vertexB"] = iLObject[iLObject[key]["next"]]["vtxIdx"];
                                    state["el"][parentChildEdgeId]["type"] = EDGE_TYPE_DE;
                                    state["el"][parentChildEdgeId]["weight"] = 1;
                                    state["el"][parentChildEdgeId]["state"] = EDGE_DEFAULT;
                                    state["el"][parentChildEdgeId]["animateHighlighted"] = false;

                                    // add an edge for doubly linked list
                                    if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                        parentChildEdgeId = iLObject[key]["vtxIdx"] + BACK_EDGE_CONST;
                                        state["el"][parentChildEdgeId] = {};

                                        state["el"][parentChildEdgeId]["vertexA"] = iLObject[iLObject[key]["next"]]["vtxIdx"];
                                        state["el"][parentChildEdgeId]["vertexB"] = iLObject[key]["vtxIdx"];
                                        state["el"][parentChildEdgeId]["type"] = EDGE_TYPE_DE;
                                        state["el"][parentChildEdgeId]["weight"] = 1;
                                        state["el"][parentChildEdgeId]["state"] = EDGE_DEFAULT;
                                        state["el"][parentChildEdgeId]["animateHighlighted"] = false;
                                    }
                                }

                                var cur = iLObject["head"],
                                    idx = 0;
                                while (cur != null) {
                                    curIdx = iLObject[cur]["vtxIdx"];
                                    // state["vl"][curIdx]["extratext"] = idx;
                                    if (idx == 0) state["vl"][curIdx]["extratext"] ="head";
                                    else if (iLObject[cur]["next"] == null) state["vl"][curIdx]["extratext"] ="tail";
                                    cur = iLObject[cur]["next"];
                                    idx++;
                                }

                                for (key in vertexTraversed) {
                                    idx = iLObject[key]["vtxIdx"];
                                    state["vl"][idx]["state"] = VERTEX_TRAVERSED;
                                }

                                for (key in edgeTraversed) {
                                    state["el"][key]["state"] = EDGE_TRAVERSED;
                                    if (state["el"][key + BACK_EDGE_CONST] != null) state["el"][key + BACK_EDGE_CONST] = EDGE_TRAVERSED;
                                }

                                return state;
                            }

                            // modified recalculateposition
                            function recalculatePosition() {
                                updatePosition(iL["head"]);

                                function updatePosition(currentVertex) {
                                    if (currentVertex == null) return;

                                    if (activeStatus =="stack") { // relayout vertical
                                        if (currentVertex == iL["head"])
                                            iL[currentVertex]["cy"] = 20;
                                        else {
                                            var curVtx = iL[currentVertex]["prev"]
                                            iL[currentVertex]["cy"] = iL[curVtx]["cy"] + 70;
                                        }
                                        iL[currentVertex]["cx"] = 350;
                                    } else { // relayout horizontal
                                        if (currentVertex == iL["head"])
                                            iL[currentVertex]["cx"] = 50;
                                        else {
                                            var curVtx = iL[currentVertex]["prev"];
                                            iL[currentVertex]["cx"] = iL[curVtx]["cx"] + 80;
                                        }
                                        iL[currentVertex]["cy"] = 50;
                                    }

                                    updatePosition(iL[currentVertex]["next"]);
                                }
                            }

                            function populatePseudocode(act) {
                              
                                switch (act) {
                                    case 4: // search
                                        $('#code1').html('if (this->is_empty()) return NOT_FOUND;');
                                        $('#code2').html('<span style="white-space: normal;">index = 0, temp = this->head;</span>');
                                        $('#code3').html('while (temp->value != input_val)');
                                        $('#code4').html('&nbsp&nbsp' + '<span style="white-space: normal;">index++, temp = temp->next;</span>');
                                        $('#code5').html('&nbsp&nbsp' + 'if (temp == nullptr)');
                                        $('#code6').html('&nbsp&nbsp&nbsp&nbsp' + 'return NOT_FOUND;');
                                        $('#code7').html('return index;');
                                        break;
                                    case 3: // peek
                                        $('#code1').html('if (this->is_empty()) return NOT_FOUND;');
                                        $('#code2').html('return this->head->value;');
                                        $('#code3').html('');
                                        $('#code4').html('');
                                        $('#code5').html('');
                                        $('#code6').html('');
                                        $('#code7').html('');
                                        break;
                                    case 9: // peek back
                                        $('#code1').html('if (is_empty()) return NOT_FOUND;');
                                        $('#code2').html('return this->tail.value;');
                                        $('#code3').html('');
                                        $('#code4').html('');
                                        $('#code5').html('');
                                        $('#code6').html('');
                                        $('#code7').html('');
                                        break;

                                    case 1: // insertHead
                                        $('#code1').html('Node* temp = new Node(input_value);');
                                        $('#code2').html('temp->next = this->head;');
                                        if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                            $('#code3').html('if (this->head != nullptr) this->head->prev = temp;');
                                            if (amountVertex == 1)
                                                $('#code4').html('this->head = temp, this->tail=this->head;');
                                            else
                                                $('#code4').html('this->head = temp;');
                                        } else if (amountVertex == 1) {
                                            $('#code3').html('this->head = temp; this->tail=this->head;');
                                            $('#code4').html('');
                                        } else {
                                            $('#code3').html('this->head = temp;');
                                            $('#code4').html('');
                                        }
                                        $('#code5').html('');
                                        $('#code6').html('');
                                        $('#code7').html('');
                                        break;
                                    case 2: // insertTail
                                        $('#code1').html('Node* temp = new Node(input_value)');
                                        if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                            $('#code2').html('this->tail->next = temp; temp->prev = this->tail;');
                                        else
                                            $('#code2').html('this->tail->next = temp;');
                                        $('#code3').html('this->tail = temp;');
                                        $('#code4').html('');
                                        $('#code5').html('');
                                        $('#code6').html('');
                                        $('#code7').html('');
                                        break;
                                    case 0: // Insert
                                        $('#code1').html('Node* pre = this->head;');
                                        $('#code2').html('for (k = 0; k < i-1; k++)');
                                        $('#code3').html('&nbsp&nbsp' + 'pre = pre->next;');
                                        $('#code4').html('Node* after = pre->next;');
                                        $('#code5').html('Node* node = new Node(v);');
                                        if ((activeStatus =="doublylist") || (activeStatus =="deque")) {
                                            $('#code6').html('<span style="white-space: normal;">node->next = after, after->prev = node;</span>');
                                            $('#code7').html('<span style="white-space: normal;">pre->next = vtx, node->prev = pre;</span>');
                                        } else {
                                            $('#code6').html('<span style="white-space: normal;">node->next = after;</span>');
                                            $('#code7').html('<span style="white-space: normal;">pre->next = node;</span>');
                                        }
                                        break;

                                    case 5: // remove head
                                        $('#code1').html('if (this->is_empty()) return;');
                                        $('#code2').html('Node* temp = this->head;');
                                        $('#code3').html('this->head = this->head->next;');
                                        $('#code4').html('delete temp;');
                                        if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                            $('#code5').html('if (this->head != nullptr) this->nead->prev = nullptr;');
                                        else
                                            $('#code5').html('');
                                        $('#code6').html('');
                                        $('#code7').html('');
                                        break;
                                    case 6: // remove tail (SLL)
                                        $('#code1').html('if (this->is_empty()) return;');
                                        $('#code2').html('Node* pre = this->head;');
                                        $('#code3').html('Node* temp = this->head->next;');
                                        $('#code4').html('while (temp->next != nullptr)');
                                        $('#code5').html('&nbsp&nbsp' + 'pre = pre->next;');
                                        $('#code6').html('pre->next = nullptr;');
                                        $('#code7').html('delete temp;');
                                        break;
                                    case 7: // remove kth
                                        $('#code1').html('if (this->is_empty()) return;');
                                        $('#code2').html('Node* pre = this->head;');
                                        $('#code3').html('for (k = 0; k < i-1; k++)');
                                        $('#code4').html('&nbsp&nbsp' + 'pre = pre->next;');
                                        $('#code5').html('Node* del = pre->next; aft=del->next;');
                                        if ((activeStatus =="doublylist") || (activeStatus =="deque"))
                                            $('#code6').html('pre->next = aft; aft->prev = pre;');
                                        else
                                            $('#code6').html('pre->next = aft; //跳过 del');
                                        $('#code7').html('delete del;');
                                        break;
                                    case 8: // remove tail (DLL, easier)
                                        $('#code1').html('if (this->is_empty()) return;');
                                        $('#code2').html('Node* temp = this->tail;');
                                        $('#code3').html('this->tail = this->tail->prev;');
                                        $('#code4').html('this->tail->next = nullptr;');
                                        $('#code5').html('delete temp;');
                                        $('#code6').html('');
                                        $('#code7').html('');
                                        break;
                                }
                            }
                        }
                  


                    // local
                    // title changing
                    function SOP() {
                        if (isPlaying) stop();
                     
                       
                        hideCodetracePanel();
                        $("#title-LL").text("链表");
                        $("#title-DLL").text("双向链表");
                    }

                   
                    var lw = new List(),
                        gw;

                    $(function() {
                        $('#play').hide();
                        gw = lw.getGraphWidget();
                        var five_modes = ["LL","Stack","Queue","DLL","Deque"];
                        $('#title-' + five_modes[Math.floor(Math.random() * 5)]).click(); // randomly open one of the five default example every time

                        var llMode = getQueryVariable("mode");
                        if (llMode.length > 0) {
                            $('#title-' + llMode).click();
                        }
                        var createLL = getQueryVariable("create");
                        if (createLL.length > 0) {
                            var newLL = createLL.split(",");
                            lw.generate(newLL);
                        }
                        var operation = getQueryVariable("operation");
                        var operationValue = getQueryVariable("operationValue");
                        var operationMode = getQueryVariable("operationMode");
                        if (operation.length > 0) {
                            switch (operation) {
                                case"insert":
                                    openInsert();
                                    insertModelingOpen(operationMode);
                                    $("#" + operationMode +"-input input").val(operationValue);
                            }
                        }

                      
                    });

                 

                    function displayList() {
                      

                        $("#search-input").css("display","");
                        $("#search-go").css("display","");

                        $("#insert-head").css("display","");
                        $("#insert-tail").css("display","");
                        $("#insert-kth").css("display","");

                        $("#remove-head").css("display","");
                        $("#remove-tail").css("display","");
                        $("#remove-kth").css("display","");
                    }

                    function displayStack() {
                    

                        $("#pushtop-input").css("display","");
                        $("#pushtop-go").css("display","");
                    }

                    function displayQueue() {
                       

                        $("#enqueueback-input").css("display","");
                        $("#enqueueback-go").css("display","");
                    }

                    function displayDeque() {
                       

                        $("#search-peek-front").css("display","");
                        $("#search-peek-back").css("display","");

                        $("#insert-deque-input").css("display","");
                        $("#insert-deque-front").css("display","");
                        $("#insert-deque-back").css("display","");

                        $("#remove-deque-front").css("display","");
                        $("#remove-deque-back").css("display","");
                    }

                  

                    function empty() {
                        if (isPlaying) stop();
                        if (lw.generateRandomFixedSize(0)) {
                            $('#progress-bar').slider("option","max", 0);
                            closeCreate();
                            isPlaying = false;
                        }
                       
                        hideCodetracePanel();
                    }

                    function random() {
                        if (isPlaying) stop();
                        if (lw.generateRandom(false)) {
                            $('#progress-bar').slider("option","max", 0);
                            closeCreate();
                            isPlaying = false;
                        }
                       
                        hideCodetracePanel();
                    }

                    function randomSorted() {
                        if (isPlaying) stop();
                        if (lw.generateRandom(true)) {
                            $('#progress-bar').slider("option","max", 0);
                            closeCreate();
                            isPlaying = false;
                        }
                       
                        hideCodetracePanel();
                    }

                    function randomFixedSize() {
                        if (isPlaying) stop();
                        var input = $('#v-create-size').val();
                        input = parseInt(input);
                        if (lw.generateRandomFixedSize(input)) {
                            $('#progress-bar').slider("option","max", 0);
                            closeCreate();
                            isPlaying = false;
                        }
                      
                        hideCodetracePanel();
                    }

                    function nonRandom() {
                        if (isPlaying) stop();
                        var input = $('#v-create-arr').val();
                        input = input.split(",");
                        if (lw.generateUserDefined(input)) {
                            $('#progress-bar').slider("option","max", 0);
                            closeCreate();
                            isPlaying = false;
                        }
                     
                        hideCodetracePanel();
                    }

                    function searchVertex(callback) {
                        if (isPlaying) stop();
                        var input = parseInt($('#v-search').val());
                        commonAction(lw.search(input, callback),"搜索" + input);
                        setTimeout(function() {
                            if (Math.random() > 0.5) // 50% chance totally random
                                $('#v-search').val(1 + Math.floor(Math.random() * 99));
                            else { // 50% something that is inside the list
                                var a = lw.getA();
                                $('#v-search').val(a[Math.floor(Math.random() * a.length)]);
                            }
                        }, 500);
                    }

                    function peekStack(callback) {
                        if (isPlaying) stop();
                        commonAction(lw.peek(true, callback), '查看最前端元素（头部）');
                    }

                    function peekQueue(callback) {
                        if (isPlaying) stop();
                        commonAction(lw.peek(true, callback), '查看前端（头部）');
                    }

                    function searchGeneric(callback) {
                        if (lw.getActiveStatus() =="stack")
                            peekStack(callback);
                        else if (lw.getActiveStatus() =="queue")
                            peekQueue(callback);
                    }

                    function peekDeque(location, callback) {
                        if (isPlaying) stop();
                        if (location =="front")
                            commonAction(lw.peek(true, callback), '查看前端（头部）');
                        else
                            commonAction(lw.peek(false, callback), '查看后端（尾部）');
                    }

                    function insertHead(callback) {
                        if (isPlaying) stop();
                        var input = parseInt($('#v-insert-head-value').val());
                        commonAction(lw.insertHead(input, callback), '将<span style="white-space: normal;">&nbsp;{input} 插入前端</span>'.replace("{input}", input));
                        setTimeout(function() {
                            $('#v-insert-head-value').val(1 + Math.floor(Math.random() * 99));
                        }, 500);
                    }

                    function insertTail(callback) {
                        if (isPlaying) stop();
                        var input = parseInt($('#v-insert-tail-value').val());
                        commonAction(lw.insertTail(input, callback), '<span style="white-space: normal;">&nbsp;将{input} 插入前端</span><br>'.replace("{input}", input));
                        setTimeout(function() {
                            $('#v-insert-tail-value').val(1 + Math.floor(Math.random() * 99));
                        }, 500);
                    }

                    function insertKth(callback) {
                        if (isPlaying) stop();
                        var index = parseInt($('#v-insert-kth').val());
                        var input = parseInt($('#v-insert-kth-value').val());
                        commonAction(lw.insertKth(index, input, callback), '<span style="white-space: normal;">&nbsp;在下标为{index}的位置插入{input}</span>'.replace("{input}", input).replace("{index}", index));
                        setTimeout(function() {
                            $('#v-insert-kth').val(1 + Math.floor(Math.random() * (lw.getN() - 1))); // [1..N-1]
                            $('#v-insert-kth-value').val(1 + Math.floor(Math.random() * 99));
                        }, 500);
                    }

                    function pushTop(callback) {
                        if (isPlaying) stop();
                        var input = $('#v-push-top-value').val();
                        commonAction(lw.insertHead(input, callback), '<span style="white-space: normal;">将 {input} 插入前端（头部）</span>'.replace("{input}", input));
                        setTimeout(function() {
                            $('#v-push-top-value').val(1 + Math.floor(Math.random() * 99));
                        }, 500);
                    }

                    function enqueueBack(callback) {
                        if (isPlaying) stop();
                        var input = $('#v-enqueue-back-value').val();
                        commonAction(lw.insertTail(input, callback), '<span style="white-space: normal;">&nbsp;将{input} 插入后端（队尾）</span><br>'.replace("{input}", input));
                        setTimeout(function() {
                            $('#v-enqueue-back-value').val(1 + Math.floor(Math.random() * 99));
                        }, 500);
                    }

                    function insertDeque(location) {
                        if (isPlaying) stop();
                        var input = $('#v-insert-deque-value').val();
                        if (location =="front")
                            commonAction(lw.insertHead(input), '<span style="white-space: normal;">&nbsp;将{input} 插入前端（队头）</span><br>'.replace("{input}", input));
                        else
                            commonAction(lw.insertTail(input), '<span style="white-space: normal;">&nbsp;将{input} 插入后端（队尾）</span><br>'.replace("{input}", input));
                        setTimeout(function() {
                            $('#v-insert-deque-value').val(1 + Math.floor(Math.random() * 99));
                        }, 500);
                    }

                    function removeHead(callback) { // PS both pop/stack and dequeue/queue also calls the same thing: remove head
                        if (isPlaying) stop();
                        commonAction(lw.removeHead(callback), '移除<span style="white-space: normal;">&nbsp;i = 0&nbsp;</span>头部');
                    }

                    function removeTail(callback) {
                        if (isPlaying) stop();
                        if (lw.getActiveStatus() =="doublylist" || lw.getActiveStatus() =="deque")
                            commonAction(lw.removeTailDLL(callback), '移除 <span style="white-space: normal;">&nbsp;i = N-1&nbsp;</span>尾部');
                        else
                            commonAction(lw.removeTail(callback), '移除 <span style="white-space: normal;">&nbsp;i = N-1&nbsp;</span>尾部');
                    }

                    function removeKth(callback) {
                        if (isPlaying) stop();
                        var input = parseInt($('#v-remove-kth').val());
                        commonAction(lw.removeKth(input, callback), '<span style="white-space: normal;">移除下标{input}</span>'.replace("{input}", input));
                        setTimeout(function() {
                            $('#v-remove-kth').val(1 + Math.floor(Math.random() * (lw.getN() - 2)));
                        }, 500); // [1..N-2]
                    }

                    function removeGeneric(callback) {
                        if ((lw.getActiveStatus() =="stack") || (lw.getActiveStatus() =="queue"))
                            removeHead(callback);
                    }

                    function removeDeque(location) {
                        if (isPlaying) stop();
                        if (location =="front")
                            commonAction(lw.removeHead(), '从前端移除（头部）');
                        else
                            commonAction(lw.removeTailDLL(), '从尾端移除（尾部）');
                    }

                  

                    // This function will be called before entering E-Lecture Mode
                    function ENTER_LECTURE_MODE() {
                        //if (lw) userGraph = lw.getGraph();
                    }

                    // This function will be called before returning to Explore Mode
                    function ENTER_EXPLORE_MODE() {
                        //loadGraph(userGraph);
                    }

                    // Lecture action functions
                    function CUSTOM_ACTION(action, data, mode) {
                        if (action == 'search') {
                            hideSlide(function() {
                                $('#v-search').val(data); // force
                                searchVertex(showSlide);
                            });
                        } else if (action == 'peek') {
                            hideSlide(function() {
                                searchGeneric(showSlide);
                            });
                        } else if (action == 'insert_head') {
                            hideSlide(function() {
                                $('#v-insert-head-value').val(data); // force
                                insertHead(showSlide);
                            });
                        } else if (action == 'insert_tail') {
                            hideSlide(function() {
                                $('#v-insert-tail-value').val(data); // force
                                insertTail(showSlide);
                            });
                        } else if (action == 'insert_kth') {
                            hideSlide(function() {
                                $('#v-insert-kth').val(data.split(",")[0]); // force
                                $('#v-insert-kth-value').val(data.split(",")[1]); // force
                                insertKth(showSlide);
                            });
                        } else if (action == 'remove_head') {
                            var a = lw.getA();
                            if (a.length > 0) {
                                hideSlide(function() {
                                    removeHead(showSlide);
                                });
                            } else
                                alert('The Linked List is already empty'); // put in variable?
                        } else if (action == 'remove_tail') {
                            var a = lw.getA();
                            if (a.length > 0) {
                                hideSlide(function() {
                                    removeTail(showSlide);
                                });
                            } else
                                alert('The Linked List is already empty'); // put in variable?
                        } else if (action == 'remove_kth') {
                            hideSlide(function() {
                                $('#v-remove-kth').val(data); // force
                                removeKth(showSlide);
                            });
                        } else if (action == 'push') {
                            hideSlide(function() {
                                $('#v-push-top-value').val(data); // force
                                pushTop(showSlide);
                            });
                        } else if (action == 'enqueue') {
                            var a = lw.getA();
                            if (a.length < 10) {
                                var randval = 1 + Math.floor(Math.random() * 99);
                                while (a.includes(randval))
                                    randval = 1 + Math.floor(Math.random() * 99);
                                hideSlide(function() {
                                    $('#v-enqueue-back-value').val(randval); // force random
                                    enqueueBack(showSlide);
                                });
                            } else
                                alert('The Linked List is already too long for this visualization'); // put in variable?
                        }
                    }
                </script>

</body>

</html>